Linux – What is the smallest x86_64 Hello World ELF binary?

What is the smallest x86_64 Hello World ELF binary?… here is a solution to the problem.

What is the smallest x86_64 Hello World ELF binary?

I tried

manually writing the smallest possible x86_64 ELF hello world program, but got a segfault when I tried to run it.

gdb says: During startup the program terminates with signal SIGSEGV, segfault.

This is a hexadecimal dump:

00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  . ELF............
00000010: 0200 3e00 0100 0000 7800 0000 0000 0000  .. >..... x.......
00000020: 4000 0000 0000 0000 0000 0000 0000 0000  @...............
00000030: 0000 0000 4000 3800 0100 0000 0000 0000  [email protected].........
00000040: 0100 0000 0500 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 3100 0000 0000 0000 3100 0000 0000 0000  1.......1.......
00000070: 0200 0000 0000 0000 b801 0000 00bf 0100  ................
00000080: 0000 be9a 0000 00ba 0a00 0000 0f05 b83c  ..."........... <
00000090: 0000 00bf 0000 0000 0f05 4865 6c6c 6f2c  .......... Hello,
000000a0: 2057 6f72 6c64 210a 00                    World!..

This is the output of readelf -a:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x78
  Start of program headers:          64 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         1
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0

There are no sections in this file.

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000031 0x0000000000000031  R E    0x2

There is no dynamic section in this file.

There are no relocations in this file.
No processor specific unwind information to decode

Dynamic symbol information is not available for displaying symbols.

No version information found in this file.

The code is as follows:

0xb8 0x01 0x00 0x00 0x00 /* mov %rax, 1 ; sys_write */
0xbf 0x01 0x00 0x00 0x00 /* mov %rdi, 1 ; STDOUT */
0xbe 0x9a 0x00 0x00 0x00 /* mov %rsi, 0x9a ; address of string */
0xba 0x0a 0x00 0x00 0x00 /* mov %rdi, 15 ; size of string */
0x0f 0x05                /* syscall */

0xb8 0x3c 0x00 0x00 0x00 /* mov %rax, 60 ; sys_exit */
0xbf 0x00 0x00 0x00 0x00 /* mov %rdi, 0 ; exit status */
0x0f 0x05                /* syscall */

The string “Hello, World!\n” follows.
I’ve been using this MOV instruction .
Attempts to use the header offset, alignment, and virtual address fields did not produce any results. manpage part is a bit confusing. I also tried comparing this binary with a binary written in assembly language, but I found no use.

Now to answer my question: can you tell me what the error is and/or how I can debug this binary?

Solution

I tried to write the smallest possible x86_64 ELF hello world program by hand

You should provide a source code for your program so that we can fix it.

gdb says: During startup program terminated with signal SIGSEGV

This is GDB

telling you that it called fork/execve to create the target program and expects the kernel to notify GDB that the program is now ready to be debugged. Instead, the kernel notifies GDB that the program has been terminated by SIGSEGV and has not yet reached its first instruction.

GDB did not anticipate this. Why is this?

This happens when the kernel looks at your executable and says “I can’t create a running program from it.”

Why is this? Because of this LOAD segment:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000031 0x0000000000000031  R E    0x2

Requires the kernel to map 0x31 bytes from offset 0 in the file to virtual address 0. But the kernel (rightfully) rejected this pointless request and terminated the program with SIGSEGV before returning from execve.

You can probably avoid this by making a file ET_DYN instead of a ET_EXEC – this will change the meaning of your program header from “map this segment to 0” to “map this segment anywhere”.

You can definitely avoid this by keeping the ET_EXEC, but changing the .p_vaddr and .p_paddr of the segment to something like 0x10000

TL;DR: Your program and file headers must make sense to the kernel, otherwise you will never boot.

Related Problems and Solutions