I tried to write the smallest possible x86_64 ELF hello world program by hand, but I receive a Segmentation fault when trying to run it.
gdb says: During startup program terminated with signal SIGSEGV, Segmentation fault.
Here is the hexdump:
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!..
Here 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.
And here is the code:
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 "Hello, World!\n" string follows immediately afterwards. I have been using this MOV instruction. Playing around with the program header offset, alignment and virtual address fields did not yield anything. The manpage is a little confusing in this section. I also tried comparing this binary to one written in assembly, but I've found nothing useful.
Now to my question: Can you tell me what the mistake is and/or how I can debug this binary?
CodePudding user response:
I tried to write the smallest possible x86_64 ELF hello world program by hand
You should provide a source for your program, so 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 expected the kernel to notify GDB that the program is now ready to be debugged. Instead, the kernel notified GDB that the program has died with SIGSEGV
, without ever reaching its first instruction.
GDB didn't expect that. Why would this happen?
This happens when the kernel looks at your executable, and says "I can't create a running program out of that".
Why is that the case here? Because this LOAD
segment:
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000031 0x0000000000000031 R E 0x2
is asking the kernel to map 0x31
bytes from offset 0
in the file to virtual address 0
. But the kernel (rightfully) refuses such nonsense request, and terminates the program with SIGSEGV
before returning from execve
.
You could probably avoid this by making the file ET_DYN
instead of ET_EXEC
-- that would change the meaning of your program header from "map this segment at 0" to "map this segment anywhere".
You could 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, or you'll never get off the ground.
CodePudding user response:
The answer that I accepted did the trick. I just want to share the new hexdump of the binary here:
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0200 3e00 0100 0000 7800 0100 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 0100 0000 0000 0000 0100 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 0001 00ba 0f00 0000 0f05 b83c ...............<
00000090: 0000 00bf 0000 0000 0f05 4865 6c6c 6f2c ..........Hello,
000000a0: 2057 6f72 6c64 210a 00 World!..
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: 0x10078
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 0x0000000000010000 0x0000000000010000
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:
0xb8, 0x01, 0x00, 0x00, 0x00, /* mov $0x1,%rax ; sys_write */
0xbf, 0x01, 0x00, 0x00, 0x00, /* mov $0x1,%rdi ; STDOUT */
0xbe, 0x9a, 0x00, 0x01, 0x00, /* mov $0x1009a,%rsi ; address of string */
0xba, 0x0f, 0x00, 0x00, 0x00, /* mov $0xf,%rdx ; size of string*/
0x0f, 0x05, /* syscall */
0xb8, 0x3c, 0x00, 0x00, 0x00, /* mov $0x3c,%rax ; sys_exit */
0xbf, 0x00, 0x00, 0x00, 0x00, /* mov $0x0,