In this post, I'll explain and investigate the Executable and Linkable Format (ELF), which is the default binary format on Linux-based systems.
To make practices, I've written a simple copy.c source file and we will investigate this:
/**
* Copying a file content to another one.
*/
#include "../linux.h"
#ifndef BUF_SIZE
#define BUF_SIZE 1024
#endif
void main(int argc, char *argv[])
{
int inputFd, outputFd, openFlags;
mode_t filePerms;
ssize_t numRead;
char buf[BUF_SIZE];
if (argc != 3 || strcmp(argv[1], "--help") == 0)
usage_error("Wrong command-line usage");
/* Open input and output files */
inputFd = open(argv[1], O_RDONLY);
if (inputFd)
syscall_error();
openFlags = O_CREAT | O_WRONLY | O_TRUNC;
filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH; /* rw-rw-rw- */
outputFd = open(argv[2], openFlags, filePerms);
if (outputFd == -1)
syscall_error();
/* Transfer data until we encounter end of input or an error */
while ((numRead == read(inputFd, buf, BUF_SIZE)) > 0)
if (write(outputFd, buf, numRead) != numRead)
syscall_error();
if (numRead == -1)
syscall_error();
if (close(inputFd) == -1)
syscall_error();
if (close(outputFd) == -1)
syscall_error();
exit(EXIT_SUCCESS);
}
Compile this program like this:
$ gcc copy.c -o copy -O0 -g
Binary Composition
Firstly, let's look at binary composition. A binary includes many headers, sections and areas that lets the CPU to run required machine instructions. Below is the 64-bit ELF binary layout:
Every ELF file starts with an executable header, which is just a structured series of bytes telling you that it's an ELF file, what kind of ELF file it is, and where in the file to find all the other contents. It is defined in /usr/include/elf.h and can be seen the executable header with readelf command:
$ readelf -h copy
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: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1160
Start of program headers: 64 (bytes into file)
Start of section headers: 17496 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 37
Section header string table index: 36
The code and data in an ELF binary are logically divided into contiguous nonoverlapping chunks called sections. Sections don't have any predetermined structure; instead, the structure of each section varies depending on the contents. Every section is described by a section header, which denotes the properties of the section and allows you to locate the bytes belonging to the section. The section headers for all sections in the binary are contained in the section header table.
Typical ELF files that you'll find on a GNU/Linux system are organized into a series of standard sections. Let's see the section names of our binary.
$ readelf --sections --wide copy
There are 37 section headers, starting at offset 0x4458:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1
[ 2] .note.gnu.property NOTE 0000000000000338 000338 000030 00 A 0 0 8
[ 3] .note.gnu.build-id NOTE 0000000000000368 000368 000024 00 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000038c 00038c 000020 00 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003b0 0003b0 000028 00 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003d8 0003d8 000180 18 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000558 000558 0000d3 00 A 0 0 1
[ 8] .gnu.version VERSYM 000000000000062c 00062c 000020 02 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000650 000650 000030 00 A 7 1 8
[10] .rela.dyn RELA 0000000000000680 000680 0000d8 18 A 6 0 8
[11] .rela.plt RELA 0000000000000758 000758 0000d8 18 AI 6 24 8
[12] .init PROGBITS 0000000000001000 001000 00001b 00 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 001020 0000a0 10 AX 0 0 16
[14] .plt.got PROGBITS 00000000000010c0 0010c0 000010 10 AX 0 0 16
[15] .plt.sec PROGBITS 00000000000010d0 0010d0 000090 10 AX 0 0 16
[16] .text PROGBITS 0000000000001160 001160 00043a 00 AX 0 0 16
[17] .fini PROGBITS 000000000000159c 00159c 00000d 00 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 002000 000040 00 A 0 0 4
[19] .eh_frame_hdr PROGBITS 0000000000002040 002040 000034 00 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002078 002078 0000a8 00 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003d78 002d78 000008 08 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003d80 002d80 000008 08 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003d88 002d88 0001f0 10 WA 7 0 8
[24] .got PROGBITS 0000000000003f78 002f78 000088 08 WA 0 0 8
[25] .data PROGBITS 0000000000004000 003000 000010 00 WA 0 0 8
[26] .bss NOBITS 0000000000004020 003010 000010 00 WA 0 0 32
[27] .comment PROGBITS 0000000000000000 003010 00002b 01 MS 0 0 1
[28] .debug_aranges PROGBITS 0000000000000000 00303b 000030 00 0 0 1
[29] .debug_info PROGBITS 0000000000000000 00306b 000472 00 0 0 1
[30] .debug_abbrev PROGBITS 0000000000000000 0034dd 000184 00 0 0 1
[31] .debug_line PROGBITS 0000000000000000 003661 00017e 00 0 0 1
[32] .debug_str PROGBITS 0000000000000000 0037df 00031a 01 MS 0 0 1
[33] .debug_line_str PROGBITS 0000000000000000 003af9 00012f 01 MS 0 0 1
[34] .symtab SYMTAB 0000000000000000 003c28 000438 18 35 18 8
[35] .strtab STRTAB 0000000000000000 004060 00028c 00 0 0 1
[36] .shstrtab STRTAB 0000000000000000 0042ec 00016a 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
For each section, readelf shows the relevant basic information, including the index, name, type of the sections. Let's focus on some important section names:
.init and .fini: The .init section contains executable code that performs initialization tasks and needs to run before any other code in the binary is executed like a constructor. .fini runs after the main program completes like a destructor.
.text: The .text section is where the main code of the program resides, so it will frequently be the main focus of your binary analysis or reverse engineering efforts.
The .bss, .data and .rodata: The program variables are kept in one or more dedicated sections, which are writable (.text is just readable). .bss is used to store uninitialized data and .data for initialized data. .rodata is also for constant (look for const keyword) variables.
Let's see the .rodata section:
$ objdump -sj .rodata -d copy
copy: file format elf64-x86-64
Contents of section .rodata:
2000 01000200 2d2d6865 6c700063 6f70792e ....--help.copy.
2010 63005772 6f6e6720 636f6d6d 616e642d c.Wrong command-
2020 6c696e65 20757361 6765002a 2a2a2025 line usage.*** %
2030 73202825 733a3a25 6429202a 2a2a0a00 s (%s::%d) ***..
Disassembly of section .rodata:
0000000000002000 <_IO_stdin_used>:
2000: 01 00 02 00 2d 2d 68 65 6c 70 00 63 6f 70 79 2e ....--help.copy.
2010: 63 00 57 72 6f 6e 67 20 63 6f 6d 6d 61 6e 64 2d c.Wrong command-
2020: 6c 69 6e 65 20 75 73 61 67 65 00 2a 2a 2a 20 25 line usage.*** %
2030: 73 20 28 25 73 3a 3a 25 64 29 20 2a 2a 2a 0a 00 s (%s::%d) ***..
The program header table provides a segment view of the binary, as opposed to the section view provided by the section header table. The section view of an ELF binary is meant for static linking purposes only.
Binary Analysis
After looked at the ELF binary composition, right now, I'll introduce the basic binary analysis in Linux. For this purpose, I will use these commands:
file
ldd
xdd
readelf
strings
strace
ltrace
objdump
gdb
file command shows the basic information about the binary itself.
$ file copy
copy: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e09844bc261dfab16c73facffe7995c19483be17, for GNU/Linux 3.2.0, with debug_info, not stripped
You can see that this binary is 64-bit ELF and host architecture is x86-64.
ldd command is used to find out on which shared object a binary depends and where (if anywhere) these dependencies are on your system.
$ ldd -v copy
linux-vdso.so.1 (0x00007ffd7da09000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000786bc4400000)
/lib64/ld-linux-x86-64.so.2 (0x0000786bc47bd000)
Version information:
./copy:
libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.34) => /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6:
ld-linux-x86-64.so.2 (GLIBC_2.2.5) => /lib64/ld-linux-x86-64.so.2
ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
With xxd command, you can see the binary at byte-level. As you guest, it is not human readable and very long. But I put the beginning and last a few lines of its output.
$ xxd copy
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0300 3e00 0100 0000 6011 0000 0000 0000 ..>.....`.......
00000020: 4000 0000 0000 0000 5844 0000 0000 0000 @.......XD......
00000030: 0000 0000 4000 3800 0d00 4000 2500 2400 ....@.8...@.%.$.
00000040: 0600 0000 0400 0000 4000 0000 0000 0000 ........@.......
... (other binary bytes) ...
00004d60: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00004d70: ec42 0000 0000 0000 6a01 0000 0000 0000 .B......j.......
00004d80: 0000 0000 0000 0000 0100 0000 0000 0000 ................
00004d90: 0000 0000 0000 0000 ........
To view the details of the ELF headers, sections, areas; readelf command is the gold command. But I've shown its usage before. So I pass it directly.
To figure out what a binary does and what kinds of inputs it expects, you can check whether the binary contains any helpful strings that can reveal its purpose with strings command.
$ strings copy | grep -E "open|read|write|close"
read
open
close
write
close
write
_IO_write_ptr
read
openFlags
_IO_write_base
_IO_read_end
_IO_read_ptr
_IO_write_end
_IO_read_base
open
write@GLIBC_2.2.5
close@GLIBC_2.2.5
read@GLIBC_2.2.5
open@GLIBC_2.2.5
strace command is used to trace the system calls when running a binary.
$ strace ./copy
execve("./copy", ["./copy"], 0x7ffe3bcf3de0 /* 58 vars */) = 0
brk(NULL) = 0x5f159129e000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7379e0da1000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=128899, ...}) = 0
mmap(NULL, 128899, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7379e0d45000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\243\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_mode=S_IFREG|0755, st_size=2125328, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2170256, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7379e0a00000
mmap(0x7379e0a28000, 1605632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7379e0a28000
mmap(0x7379e0bb0000, 323584, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b0000) = 0x7379e0bb0000
mmap(0x7379e0bff000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1fe000) = 0x7379e0bff000
mmap(0x7379e0c05000, 52624, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7379e0c05000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7379e0d42000
arch_prctl(ARCH_SET_FS, 0x7379e0d42740) = 0
set_tid_address(0x7379e0d42a10) = 22680
set_robust_list(0x7379e0d42a20, 24) = 0
rseq(0x7379e0d43060, 0x20, 0, 0x53053053) = 0
mprotect(0x7379e0bff000, 16384, PROT_READ) = 0
mprotect(0x5f156087f000, 4096, PROT_READ) = 0
mprotect(0x7379e0d9b000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7379e0d45000, 128899) = 0
write(2, "*** Wrong command-line usage (co"..., 46*** Wrong command-line usage (copy.c::17) ***
) = 46
exit_group(1) = ?
+++ exited with 1 +++
lstrace command, as opposed to strace, is used to trace the library calls.
$ ltrace ./copy
fprintf(0x796bcfc044e0, "*** %s (%s::%d) ***\n", "Wrong command-line usage", "copy.c", 17*** Wrong command-line usage (copy.c::17) ***
) = 46
exit(1 <no return ...>
+++ exited (status 1) +++
objdump command is another popular tool when analyzing a binary content. It's multi-purpose command and can be used for numerous stuffs. I just show here the disassemble functionality.
$ objdump --disassemble copy
copy: file format elf64-x86-64
Disassembly of section .init:
0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__@Base>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 call *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 ret
Disassembly of section .plt:
0000000000001020 <.plt>:
1020: ff 35 5a 2f 00 00 push 0x2f5a(%rip) # 3f80 <_GLOBAL_OFFSET_TABLE_+0x8>
1026: ff 25 5c 2f 00 00 jmp *0x2f5c(%rip) # 3f88 <_GLOBAL_OFFSET_TABLE_+0x10>
102c: 0f 1f 40 00 nopl 0x0(%rax)
1030: f3 0f 1e fa endbr64
1034: 68 00 00 00 00 push $0x0
1039: e9 e2 ff ff ff jmp 1020 <_init+0x20>
103e: 66 90 xchg %ax,%ax
1040: f3 0f 1e fa endbr64
1044: 68 01 00 00 00 push $0x1
1049: e9 d2 ff ff ff jmp 1020 <_init+0x20>
104e: 66 90 xchg %ax,%ax
1050: f3 0f 1e fa endbr64
1054: 68 02 00 00 00 push $0x2
1059: e9 c2 ff ff ff jmp 1020 <_init+0x20>
105e: 66 90 xchg %ax,%ax
1060: f3 0f 1e fa endbr64
1064: 68 03 00 00 00 push $0x3
1069: e9 b2 ff ff ff jmp 1020 <_init+0x20>
106e: 66 90 xchg %ax,%ax
1070: f3 0f 1e fa endbr64
1074: 68 04 00 00 00 push $0x4
1079: e9 a2 ff ff ff jmp 1020 <_init+0x20>
107e: 66 90 xchg %ax,%ax
1080: f3 0f 1e fa endbr64
1084: 68 05 00 00 00 push $0x5
1089: e9 92 ff ff ff jmp 1020 <_init+0x20>
108e: 66 90 xchg %ax,%ax
1090: f3 0f 1e fa endbr64
1094: 68 06 00 00 00 push $0x6
1099: e9 82 ff ff ff jmp 1020 <_init+0x20>
109e: 66 90 xchg %ax,%ax
10a0: f3 0f 1e fa endbr64
10a4: 68 07 00 00 00 push $0x7
10a9: e9 72 ff ff ff jmp 1020 <_init+0x20>
10ae: 66 90 xchg %ax,%ax
10b0: f3 0f 1e fa endbr64
10b4: 68 08 00 00 00 push $0x8
10b9: e9 62 ff ff ff jmp 1020 <_init+0x20>
10be: 66 90 xchg %ax,%ax
Disassembly of section .plt.got:
00000000000010c0 <__cxa_finalize@plt>:
10c0: f3 0f 1e fa endbr64
10c4: ff 25 2e 2f 00 00 jmp *0x2f2e(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
10ca: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
Disassembly of section .plt.sec:
00000000000010d0 <__errno_location@plt>:
10d0: f3 0f 1e fa endbr64
10d4: ff 25 b6 2e 00 00 jmp *0x2eb6(%rip) # 3f90 <__errno_location@GLIBC_2.2.5>
10da: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
00000000000010e0 <write@plt>:
10e0: f3 0f 1e fa endbr64
10e4: ff 25 ae 2e 00 00 jmp *0x2eae(%rip) # 3f98 <write@GLIBC_2.2.5>
10ea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
00000000000010f0 <close@plt>:
10f0: f3 0f 1e fa endbr64
10f4: ff 25 a6 2e 00 00 jmp *0x2ea6(%rip) # 3fa0 <close@GLIBC_2.2.5>
10fa: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000001100 <read@plt>:
1100: f3 0f 1e fa endbr64
1104: ff 25 9e 2e 00 00 jmp *0x2e9e(%rip) # 3fa8 <read@GLIBC_2.2.5>
110a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000001110 <strcmp@plt>:
1110: f3 0f 1e fa endbr64
1114: ff 25 96 2e 00 00 jmp *0x2e96(%rip) # 3fb0 <strcmp@GLIBC_2.2.5>
111a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000001120 <fprintf@plt>:
1120: f3 0f 1e fa endbr64
1124: ff 25 8e 2e 00 00 jmp *0x2e8e(%rip) # 3fb8 <fprintf@GLIBC_2.2.5>
112a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000001130 <open@plt>:
1130: f3 0f 1e fa endbr64
1134: ff 25 86 2e 00 00 jmp *0x2e86(%rip) # 3fc0 <open@GLIBC_2.2.5>
113a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000001140 <exit@plt>:
1140: f3 0f 1e fa endbr64
1144: ff 25 7e 2e 00 00 jmp *0x2e7e(%rip) # 3fc8 <exit@GLIBC_2.2.5>
114a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000001150 <strerror@plt>:
1150: f3 0f 1e fa endbr64
1154: ff 25 76 2e 00 00 jmp *0x2e76(%rip) # 3fd0 <strerror@GLIBC_2.2.5>
115a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
Disassembly of section .text:
0000000000001160 <_start>:
1160: f3 0f 1e fa endbr64
1164: 31 ed xor %ebp,%ebp
1166: 49 89 d1 mov %rdx,%r9
1169: 5e pop %rsi
116a: 48 89 e2 mov %rsp,%rdx
116d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1171: 50 push %rax
1172: 54 push %rsp
1173: 45 31 c0 xor %r8d,%r8d
1176: 31 c9 xor %ecx,%ecx
1178: 48 8d 3d ca 00 00 00 lea 0xca(%rip),%rdi # 1249 <main>
117f: ff 15 53 2e 00 00 call *0x2e53(%rip) # 3fd8 <__libc_start_main@GLIBC_2.34>
1185: f4 hlt
1186: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
118d: 00 00 00
0000000000001190 <deregister_tm_clones>:
1190: 48 8d 3d 79 2e 00 00 lea 0x2e79(%rip),%rdi # 4010 <__TMC_END__>
1197: 48 8d 05 72 2e 00 00 lea 0x2e72(%rip),%rax # 4010 <__TMC_END__>
119e: 48 39 f8 cmp %rdi,%rax
11a1: 74 15 je 11b8 <deregister_tm_clones+0x28>
11a3: 48 8b 05 36 2e 00 00 mov 0x2e36(%rip),%rax # 3fe0 <_ITM_deregisterTMCloneTable@Base>
11aa: 48 85 c0 test %rax,%rax
11ad: 74 09 je 11b8 <deregister_tm_clones+0x28>
11af: ff e0 jmp *%rax
11b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
11b8: c3 ret
11b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000000011c0 <register_tm_clones>:
11c0: 48 8d 3d 49 2e 00 00 lea 0x2e49(%rip),%rdi # 4010 <__TMC_END__>
11c7: 48 8d 35 42 2e 00 00 lea 0x2e42(%rip),%rsi # 4010 <__TMC_END__>
11ce: 48 29 fe sub %rdi,%rsi
11d1: 48 89 f0 mov %rsi,%rax
11d4: 48 c1 ee 3f shr $0x3f,%rsi
11d8: 48 c1 f8 03 sar $0x3,%rax
11dc: 48 01 c6 add %rax,%rsi
11df: 48 d1 fe sar $1,%rsi
11e2: 74 14 je 11f8 <register_tm_clones+0x38>
11e4: 48 8b 05 05 2e 00 00 mov 0x2e05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable@Base>
11eb: 48 85 c0 test %rax,%rax
11ee: 74 08 je 11f8 <register_tm_clones+0x38>
11f0: ff e0 jmp *%rax
11f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
11f8: c3 ret
11f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001200 <__do_global_dtors_aux>:
1200: f3 0f 1e fa endbr64
1204: 80 3d 1d 2e 00 00 00 cmpb $0x0,0x2e1d(%rip) # 4028 <completed.0>
120b: 75 2b jne 1238 <__do_global_dtors_aux+0x38>
120d: 55 push %rbp
120e: 48 83 3d e2 2d 00 00 cmpq $0x0,0x2de2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1215: 00
1216: 48 89 e5 mov %rsp,%rbp
1219: 74 0c je 1227 <__do_global_dtors_aux+0x27>
121b: 48 8b 3d e6 2d 00 00 mov 0x2de6(%rip),%rdi # 4008 <__dso_handle>
1222: e8 99 fe ff ff call 10c0 <__cxa_finalize@plt>
1227: e8 64 ff ff ff call 1190 <deregister_tm_clones>
122c: c6 05 f5 2d 00 00 01 movb $0x1,0x2df5(%rip) # 4028 <completed.0>
1233: 5d pop %rbp
1234: c3 ret
1235: 0f 1f 00 nopl (%rax)
1238: c3 ret
1239: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001240 <frame_dummy>:
1240: f3 0f 1e fa endbr64
1244: e9 77 ff ff ff jmp 11c0 <register_tm_clones>
0000000000001249 <main>:
1249: f3 0f 1e fa endbr64
124d: 55 push %rbp
124e: 48 89 e5 mov %rsp,%rbp
1251: 48 81 ec 40 04 00 00 sub $0x440,%rsp
1258: 89 bd cc fb ff ff mov %edi,-0x434(%rbp)
125e: 48 89 b5 c0 fb ff ff mov %rsi,-0x440(%rbp)
1265: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
126c: 00 00
126e: 48 89 45 f8 mov %rax,-0x8(%rbp)
1272: 31 c0 xor %eax,%eax
1274: 83 bd cc fb ff ff 03 cmpl $0x3,-0x434(%rbp)
127b: 75 24 jne 12a1 <main+0x58>
127d: 48 8b 85 c0 fb ff ff mov -0x440(%rbp),%rax
1284: 48 83 c0 08 add $0x8,%rax
1288: 48 8b 00 mov (%rax),%rax
128b: 48 8d 15 72 0d 00 00 lea 0xd72(%rip),%rdx # 2004 <_IO_stdin_used+0x4>
1292: 48 89 d6 mov %rdx,%rsi
1295: 48 89 c7 mov %rax,%rdi
1298: e8 73 fe ff ff call 1110 <strcmp@plt>
129d: 85 c0 test %eax,%eax
129f: 75 3c jne 12dd <main+0x94>
12a1: 48 8b 05 78 2d 00 00 mov 0x2d78(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
12a8: 41 b8 11 00 00 00 mov $0x11,%r8d
12ae: 48 8d 15 56 0d 00 00 lea 0xd56(%rip),%rdx # 200b <_IO_stdin_used+0xb>
12b5: 48 89 d1 mov %rdx,%rcx
12b8: 48 8d 15 53 0d 00 00 lea 0xd53(%rip),%rdx # 2012 <_IO_stdin_used+0x12>
12bf: 48 8d 35 65 0d 00 00 lea 0xd65(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
12c6: 48 89 c7 mov %rax,%rdi
12c9: b8 00 00 00 00 mov $0x0,%eax
12ce: e8 4d fe ff ff call 1120 <fprintf@plt>
12d3: bf 01 00 00 00 mov $0x1,%edi
12d8: e8 63 fe ff ff call 1140 <exit@plt>
12dd: 48 8b 85 c0 fb ff ff mov -0x440(%rbp),%rax
12e4: 48 83 c0 08 add $0x8,%rax
12e8: 48 8b 00 mov (%rax),%rax
12eb: be 00 00 00 00 mov $0x0,%esi
12f0: 48 89 c7 mov %rax,%rdi
12f3: b8 00 00 00 00 mov $0x0,%eax
12f8: e8 33 fe ff ff call 1130 <open@plt>
12fd: 89 85 d8 fb ff ff mov %eax,-0x428(%rbp)
1303: 83 bd d8 fb ff ff 00 cmpl $0x0,-0x428(%rbp)
130a: 74 49 je 1355 <main+0x10c>
130c: e8 bf fd ff ff call 10d0 <__errno_location@plt>
1311: 8b 00 mov (%rax),%eax
1313: 89 c7 mov %eax,%edi
1315: e8 36 fe ff ff call 1150 <strerror@plt>
131a: 48 89 c6 mov %rax,%rsi
131d: 48 8b 05 fc 2c 00 00 mov 0x2cfc(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
1324: 41 b8 17 00 00 00 mov $0x17,%r8d
132a: 48 8d 15 da 0c 00 00 lea 0xcda(%rip),%rdx # 200b <_IO_stdin_used+0xb>
1331: 48 89 d1 mov %rdx,%rcx
1334: 48 89 f2 mov %rsi,%rdx
1337: 48 8d 35 ed 0c 00 00 lea 0xced(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
133e: 48 89 c7 mov %rax,%rdi
1341: b8 00 00 00 00 mov $0x0,%eax
1346: e8 d5 fd ff ff call 1120 <fprintf@plt>
134b: bf 01 00 00 00 mov $0x1,%edi
1350: e8 eb fd ff ff call 1140 <exit@plt>
1355: c7 85 dc fb ff ff 41 movl $0x241,-0x424(%rbp)
135c: 02 00 00
135f: c7 85 e0 fb ff ff b6 movl $0x1b6,-0x420(%rbp)
1366: 01 00 00
1369: 48 8b 85 c0 fb ff ff mov -0x440(%rbp),%rax
1370: 48 83 c0 10 add $0x10,%rax
1374: 48 8b 00 mov (%rax),%rax
1377: 8b 95 e0 fb ff ff mov -0x420(%rbp),%edx
137d: 8b 8d dc fb ff ff mov -0x424(%rbp),%ecx
1383: 89 ce mov %ecx,%esi
1385: 48 89 c7 mov %rax,%rdi
1388: b8 00 00 00 00 mov $0x0,%eax
138d: e8 9e fd ff ff call 1130 <open@plt>
1392: 89 85 e4 fb ff ff mov %eax,-0x41c(%rbp)
1398: 83 bd e4 fb ff ff ff cmpl $0xffffffff,-0x41c(%rbp)
139f: 0f 85 b9 00 00 00 jne 145e <main+0x215>
13a5: e8 26 fd ff ff call 10d0 <__errno_location@plt>
13aa: 8b 00 mov (%rax),%eax
13ac: 89 c7 mov %eax,%edi
13ae: e8 9d fd ff ff call 1150 <strerror@plt>
13b3: 48 89 c6 mov %rax,%rsi
13b6: 48 8b 05 63 2c 00 00 mov 0x2c63(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
13bd: 41 b8 1f 00 00 00 mov $0x1f,%r8d
13c3: 48 8d 15 41 0c 00 00 lea 0xc41(%rip),%rdx # 200b <_IO_stdin_used+0xb>
13ca: 48 89 d1 mov %rdx,%rcx
13cd: 48 89 f2 mov %rsi,%rdx
13d0: 48 8d 35 54 0c 00 00 lea 0xc54(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
13d7: 48 89 c7 mov %rax,%rdi
13da: b8 00 00 00 00 mov $0x0,%eax
13df: e8 3c fd ff ff call 1120 <fprintf@plt>
13e4: bf 01 00 00 00 mov $0x1,%edi
13e9: e8 52 fd ff ff call 1140 <exit@plt>
13ee: 48 8b 95 e8 fb ff ff mov -0x418(%rbp),%rdx
13f5: 48 8d 8d f0 fb ff ff lea -0x410(%rbp),%rcx
13fc: 8b 85 e4 fb ff ff mov -0x41c(%rbp),%eax
1402: 48 89 ce mov %rcx,%rsi
1405: 89 c7 mov %eax,%edi
1407: e8 d4 fc ff ff call 10e0 <write@plt>
140c: 48 39 85 e8 fb ff ff cmp %rax,-0x418(%rbp)
1413: 74 49 je 145e <main+0x215>
1415: e8 b6 fc ff ff call 10d0 <__errno_location@plt>
141a: 8b 00 mov (%rax),%eax
141c: 89 c7 mov %eax,%edi
141e: e8 2d fd ff ff call 1150 <strerror@plt>
1423: 48 89 c6 mov %rax,%rsi
1426: 48 8b 05 f3 2b 00 00 mov 0x2bf3(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
142d: 41 b8 25 00 00 00 mov $0x25,%r8d
1433: 48 8d 15 d1 0b 00 00 lea 0xbd1(%rip),%rdx # 200b <_IO_stdin_used+0xb>
143a: 48 89 d1 mov %rdx,%rcx
143d: 48 89 f2 mov %rsi,%rdx
1440: 48 8d 35 e4 0b 00 00 lea 0xbe4(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
1447: 48 89 c7 mov %rax,%rdi
144a: b8 00 00 00 00 mov $0x0,%eax
144f: e8 cc fc ff ff call 1120 <fprintf@plt>
1454: bf 01 00 00 00 mov $0x1,%edi
1459: e8 e2 fc ff ff call 1140 <exit@plt>
145e: 48 8d 8d f0 fb ff ff lea -0x410(%rbp),%rcx
1465: 8b 85 d8 fb ff ff mov -0x428(%rbp),%eax
146b: ba 00 04 00 00 mov $0x400,%edx
1470: 48 89 ce mov %rcx,%rsi
1473: 89 c7 mov %eax,%edi
1475: e8 86 fc ff ff call 1100 <read@plt>
147a: 48 39 85 e8 fb ff ff cmp %rax,-0x418(%rbp)
1481: 0f 84 67 ff ff ff je 13ee <main+0x1a5>
1487: 48 83 bd e8 fb ff ff cmpq $0xffffffffffffffff,-0x418(%rbp)
148e: ff
148f: 75 49 jne 14da <main+0x291>
1491: e8 3a fc ff ff call 10d0 <__errno_location@plt>
1496: 8b 00 mov (%rax),%eax
1498: 89 c7 mov %eax,%edi
149a: e8 b1 fc ff ff call 1150 <strerror@plt>
149f: 48 89 c6 mov %rax,%rsi
14a2: 48 8b 05 77 2b 00 00 mov 0x2b77(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
14a9: 41 b8 27 00 00 00 mov $0x27,%r8d
14af: 48 8d 15 55 0b 00 00 lea 0xb55(%rip),%rdx # 200b <_IO_stdin_used+0xb>
14b6: 48 89 d1 mov %rdx,%rcx
14b9: 48 89 f2 mov %rsi,%rdx
14bc: 48 8d 35 68 0b 00 00 lea 0xb68(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
14c3: 48 89 c7 mov %rax,%rdi
14c6: b8 00 00 00 00 mov $0x0,%eax
14cb: e8 50 fc ff ff call 1120 <fprintf@plt>
14d0: bf 01 00 00 00 mov $0x1,%edi
14d5: e8 66 fc ff ff call 1140 <exit@plt>
14da: 8b 85 d8 fb ff ff mov -0x428(%rbp),%eax
14e0: 89 c7 mov %eax,%edi
14e2: e8 09 fc ff ff call 10f0 <close@plt>
14e7: 83 f8 ff cmp $0xffffffff,%eax
14ea: 75 49 jne 1535 <main+0x2ec>
14ec: e8 df fb ff ff call 10d0 <__errno_location@plt>
14f1: 8b 00 mov (%rax),%eax
14f3: 89 c7 mov %eax,%edi
14f5: e8 56 fc ff ff call 1150 <strerror@plt>
14fa: 48 89 c6 mov %rax,%rsi
14fd: 48 8b 05 1c 2b 00 00 mov 0x2b1c(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
1504: 41 b8 2a 00 00 00 mov $0x2a,%r8d
150a: 48 8d 15 fa 0a 00 00 lea 0xafa(%rip),%rdx # 200b <_IO_stdin_used+0xb>
1511: 48 89 d1 mov %rdx,%rcx
1514: 48 89 f2 mov %rsi,%rdx
1517: 48 8d 35 0d 0b 00 00 lea 0xb0d(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
151e: 48 89 c7 mov %rax,%rdi
1521: b8 00 00 00 00 mov $0x0,%eax
1526: e8 f5 fb ff ff call 1120 <fprintf@plt>
152b: bf 01 00 00 00 mov $0x1,%edi
1530: e8 0b fc ff ff call 1140 <exit@plt>
1535: 8b 85 e4 fb ff ff mov -0x41c(%rbp),%eax
153b: 89 c7 mov %eax,%edi
153d: e8 ae fb ff ff call 10f0 <close@plt>
1542: 83 f8 ff cmp $0xffffffff,%eax
1545: 75 49 jne 1590 <main+0x347>
1547: e8 84 fb ff ff call 10d0 <__errno_location@plt>
154c: 8b 00 mov (%rax),%eax
154e: 89 c7 mov %eax,%edi
1550: e8 fb fb ff ff call 1150 <strerror@plt>
1555: 48 89 c6 mov %rax,%rsi
1558: 48 8b 05 c1 2a 00 00 mov 0x2ac1(%rip),%rax # 4020 <stderr@GLIBC_2.2.5>
155f: 41 b8 2c 00 00 00 mov $0x2c,%r8d
1565: 48 8d 15 9f 0a 00 00 lea 0xa9f(%rip),%rdx # 200b <_IO_stdin_used+0xb>
156c: 48 89 d1 mov %rdx,%rcx
156f: 48 89 f2 mov %rsi,%rdx
1572: 48 8d 35 b2 0a 00 00 lea 0xab2(%rip),%rsi # 202b <_IO_stdin_used+0x2b>
1579: 48 89 c7 mov %rax,%rdi
157c: b8 00 00 00 00 mov $0x0,%eax
1581: e8 9a fb ff ff call 1120 <fprintf@plt>
1586: bf 01 00 00 00 mov $0x1,%edi
158b: e8 b0 fb ff ff call 1140 <exit@plt>
1590: bf 00 00 00 00 mov $0x0,%edi
1595: e8 a6 fb ff ff call 1140 <exit@plt>
Disassembly of section .fini:
000000000000159c <_fini>:
159c: f3 0f 1e fa endbr64
15a0: 48 83 ec 08 sub $0x8,%rsp
15a4: 48 83 c4 08 add $0x8,%rsp
15a8: c3 ret
In here, at most left side, you see the address the machine instructions in the its virtual memory layout. At center, there are the instruction opcodes. At most right side, the corresponding assembly commands exist.
GDB is the super-useful and standard debugger onto GNU/Linux. I think that it deserves to be topics of another post. So I will explain it later.
Top comments (0)