Introduction
GCC is one of the most used compilers, when learning C you most likely faced the well known “hello world”. However when trying to understand how ELF works I realised about the size differences between binaries compiled and the least needed, on the first case it has 16608 bytes when only about 100 are necessary to make it run.
Environment
In case you want to replicate this research here is the environment used:
gcc version 10.2.1 20210110 (Debian 10.2.1-6)
Linux debian 5.10.0-15-amd64 #1 SMP Debian 5.10.120-1 (2022-06-09) x86_64 GNU/Linux
Source code used to test it out:
|
|
Here are all the preprocessor directives and flags used (output from gcc -v hello.c
):
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 10.2.1-6' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-10-Km9U7s/gcc-10-10.2.1/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-10-Km9U7s/gcc-10-10.2.1/debian/tmp-gcn/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-mutex
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.1 20210110 (Debian 10.2.1-6)
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/10/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -version -fasynchronous-unwind-tables -o /tmp/ccPlNpEc.s
GNU C17 (Debian 10.2.1-6) version 10.2.1 20210110 (x86_64-linux-gnu)
compiled by GNU C version 10.2.1 20210110, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.0, isl version isl-0.23-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/10/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/10/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C17 (Debian 10.2.1-6) version 10.2.1 20210110 (x86_64-linux-gnu)
compiled by GNU C version 10.2.1 20210110, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.0, isl version isl-0.23-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 1f803793fa2e3418c492b25e7d3eac2f
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccj7Y1pe.o /tmp/ccPlNpEc.s
GNU assembler version 2.35.2 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.35.2
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/:/usr/lib/gcc/x86_64-linux-gnu/10/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/10/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/:/usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/10/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/10/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/10/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper -plugin-opt=-fresolution=/tmp/ccGkwgEd.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie /usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/10/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/10 -L/usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/10/../../.. /tmp/ccj7Y1pe.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
Program Header
Using readelf
we can easily analyze how it was generated:
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 (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1050
Start of program headers: 64 (bytes into file)
Start of section headers: 14688 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 11
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
From the above result there is not much to point out, except the type generated. As a result of using -pie
by default it does not create a EXEC
type ELF as you may expect.
Sections
Sections comprise all information needed for linking a target object file in order to build a working executable. They are needed on linktime, not on runtime.
Sections generated are shown in the following table.
Name | Type | Address | Offset | Size | EntSize | Flags | Link | Info | Align | |
---|---|---|---|---|---|---|---|---|---|---|
0 | NULL | 0000000000000000 | 00000000 | 0000000000000000 | 0000000000000000 | 0 | 0 | 0 | ||
1 | .interp | PROGBITS | 00000000000002a8 | 000002a8 | 000000000000001c | 0000000000000000 | A | 0 | 0 | 1 |
2 | .note.gnu.build-id | NOTE | 00000000000002c4 | 000002c4 | 0000000000000024 | 0000000000000000 | A | 0 | 0 | 4 |
3 | .note.ABI-tag | NOTE | 00000000000002e8 | 000002e8 | 0000000000000020 | 0000000000000000 | A | 0 | 0 | 4 |
4 | .gnu.hash | GNU_HASH | 0000000000000308 | 00000308 | 0000000000000024 | 0000000000000000 | A | 5 | 0 | 8 |
5 | .dynsym | DYNSYM | 0000000000000330 | 00000330 | 00000000000000a8 | 0000000000000018 | A | 6 | 1 | 8 |
6 | .dynstr | STRTAB | 00000000000003d8 | 000003d8 | 0000000000000084 | 0000000000000000 | A | 0 | 0 | 1 |
7 | .gnu.version | VERSYM | 000000000000045c | 0000045c | 000000000000000e | 0000000000000002 | A | 5 | 0 | 2 |
8 | .gnu.version_r | VERNEED | 0000000000000470 | 00000470 | 0000000000000020 | 0000000000000000 | A | 6 | 1 | 8 |
9 | .rela.dyn | RELA | 0000000000000490 | 00000490 | 00000000000000c0 | 0000000000000018 | A | 5 | 0 | 8 |
10 | .rela.plt | RELA | 0000000000000550 | 00000550 | 0000000000000018 | 0000000000000018 | AI | 5 | 23 | 8 |
11 | .init | PROGBITS | 0000000000001000 | 00001000 | 0000000000000017 | 0000000000000000 | AX | 0 | 0 | 4 |
12 | .plt | PROGBITS | 0000000000001020 | 00001020 | 0000000000000020 | 0000000000000010 | AX | 0 | 0 | 16 |
13 | .plt.got | PROGBITS | 0000000000001040 | 00001040 | 0000000000000008 | 0000000000000008 | AX | 0 | 0 | 8 |
14 | .text | PROGBITS | 0000000000001050 | 00001050 | 0000000000000171 | 0000000000000000 | AX | 0 | 0 | 16 |
15 | .fini | PROGBITS | 00000000000011c4 | 000011c4 | 0000000000000009 | 0000000000000000 | AX | 0 | 0 | 4 |
16 | .rodata | PROGBITS | 0000000000002000 | 00002000 | 0000000000000011 | 0000000000000000 | A | 0 | 0 | 4 |
17 | .eh_frame_hdr | PROGBITS | 0000000000002014 | 00002014 | 000000000000003c | 0000000000000000 | A | 0 | 0 | 4 |
18 | .eh_frame | PROGBITS | 0000000000002050 | 00002050 | 0000000000000108 | 0000000000000000 | A | 0 | 0 | 8 |
19 | .init_array | INIT_ARRAY | 0000000000003de8 | 00002de8 | 0000000000000008 | 0000000000000008 | WA | 0 | 0 | 8 |
20 | .fini_array | FINI_ARRAY | 0000000000003df0 | 00002df0 | 0000000000000008 | 0000000000000008 | WA | 0 | 0 | 8 |
21 | .dynamic | DYNAMIC | 0000000000003df8 | 00002df8 | 00000000000001e0 | 0000000000000010 | WA | 6 | 0 | 8 |
22 | .got | PROGBITS | 0000000000003fd8 | 00002fd8 | 0000000000000028 | 0000000000000008 | WA | 0 | 0 | 8 |
23 | .got.plt | PROGBITS | 0000000000004000 | 00003000 | 0000000000000020 | 0000000000000008 | WA | 0 | 0 | 8 |
24 | .data | PROGBITS | 0000000000004020 | 00003020 | 0000000000000010 | 0000000000000000 | WA | 0 | 0 | 8 |
25 | .bss | NOBITS | 0000000000000000 | 00003030 | 0000000000000008 | 0000000000000000 | WA | 0 | 0 | 1 |
26 | .comment | PROGBITS | 0000000000000000 | 00003030 | 0000000000000027 | 0000000000000001 | MS | 0 | 0 | 1 |
27 | .symtab | SYMTAB | 0000000000000000 | 00003058 | 0000000000000600 | 0000000000000018 | 28 | 45 | 8 | |
28 | .strtab | STRTAB | 0000000000000000 | 00003658 | 00000000000001ff | 0000000000000000 | 0 | 0 | 1 | |
29 | .shstrtab | STRTAB | 0000000000000000 | 00003857 | 0000000000000107 | 0000000000000000 | 0 | 0 | 1 |
note
A vendor or system engineer might need to mark an object file with special information that other programs can check for conformance or compatibility. For core dumps, this segment contains the status of the process (when the core dump is created). They are of type SHT_NOTE and use Elf64_Nhdr struct.
|
|
Despite Elf64_Nhdr having only 3 fields in reality there is two more, name and desc according to ELF specification. This may be to avoid dinamically sized structs.
Similarly in genelf.c it defines Elf_Note struct, adding a field for both name and desc fields. Keeping a fixed size structure and extending its content in the bnote struct.
.note.gnu.build-id
This section is generated using --build-id
flag. The build ID is a 160-bit SHA1 string computed over the elf header bits and section contents in the file. However, there are other alternatives such as the use of urandom or md5 as seen in genelf.c linux source code.
Here are the contents of this particular build.
00000000: 0400 0000 1400 0000 0300 0000 474e 5500 ............GNU.
00000010: 91f3 d034 afde beba c471 f066 adbb 7d68 ...4.....q.f..}h
00000020: 8fde 7447 ..tG
With their corresponding table displaying each attribute.
namesz | descsz | type | name | desc |
---|---|---|---|---|
04000000 | 14000000 | 0x03000000 | 0x474e5500 | 0x91f3d034afdebebac471f066adbb7d688fde7447 |
.note.ABI-tag
This section is smaller.
00000000: 0400 0000 1000 0000 0100 0000 474e 5500 ............GNU.
00000010: 0000 0000 0300 0000 0200 0000 0000 0000 ................
Let’s check again their attributes:
namesz | descsz | type | name | desc |
---|---|---|---|---|
04000000 | 10000000 | 0x01000000 | 0x474e5500 | 0x0000000003000000020000000000 |
In this case descsz
field is not a hash, instead its composed of some more fields as explained in elf man pages:
NT_GNU_ABI_TAG
Operating system (OS) ABI information. The
desc field will be 4 words:
• word 0: OS descriptor (ELF_NOTE_OS_LINUX,
ELF_NOTE_OS_GNU, and so on)`
• word 1: major version of the ABI
• word 2: minor version of the ABI
• word 3: subminor version of the ABI
Summaring up it uses linux (ELF_NOTE_OS_LINUX) with version 3.2.
gnu
GNU systems uses this sections in GNU-compatible software.
.gnu.hash
This section consists of four separate parts, in order:
- Header: An array of (4) 32-bit words providing section parameters.
- nbuckets: The number of hash buckets. In this case
0200 0000
(little endian), meaning that there are two buckets. - symndx: The dynamic symbol table has dynsymcount symbols. The index of the first symbol in the dynamic symbol table that is to be accessible via the hash table is specified in symndx. There are (dynsymcount - symndx) symbols accessible via the hash table.
- maskwords: The number of ELFCLASS sized words in the Bloom filter portion of the hash table section. This value must be non-zero, and must be a power of 2.
- shift2: A shift count used by the Bloom filter.
- nbuckets: The number of hash buckets. In this case
- Bloom filter: Bloom filters are probabilistic, meaning that false positives are possible, but false negatives are not. This filter is used to rapidly reject symbol names that will not be found in the object, avoiding the more expensive hash lookup operation.
- Hash buckets: An array of nbuckets 32-bit hash buckets
- Hash Values: An array of (dynsymcount - symndx) 32-bit hash chain values.
- When a Bloom filter has all of its bits set, all tests result in a True (accept) value. The GNU linker takes advantage of this by issuing a single word Bloom filter with all bits set when it wants to “disable” the Bloom filter. The filter is still there, and is still used, at minimal overhead, but it lets everything through.
- A Bloom filter with no bits set will return False in all cases. This case is relatively rare in ELF files, as an object that exports no symbols has limited application. However, sometimes objects are built this way, relying on init/fini sections to cause code from the object to run.
.gnu.version
The version symbol section is defined by the type SHT_SUNW_versym. This section consists of an array of elements of type Elf64_Half.
The number of elements of the array must equal the number of symbol table entries that are contained in the .dynsym section. Each element of the array contains a single index that can have the values shown below.
Name | Value | Description |
---|---|---|
VER_NDX_LOCAL | 0 | Symbol has local scope. |
VER_NDX_GLOBAL | 1 | Symbol has global scope and is assigned to the base version definition. |
>1 | Symbol has global scope and is assigned to a user-defined version definition, SHT_SUNW_verdef, or a version dependency, SHT_SUNW_verneed. |
From the section’s content we can see that there are 4 local symbols and 3 symbol defined in SHT_GNU_verneed section as there isn’t any SHT_SUNW_verdef in the binary.
00000000: 0000 0000 0200 0200 0000 0000 0200 ..............
.gnu.version_r
Symbol definitions are contained in the special section .gnu.version_r which has a section type of SHT_GNU_verneed. The number of entries in this section is contained in the DT_VERNEEDNUM entry of the Dynamic Section (.dynamic).
The section contains an array of Elf64_Verneed structures.
Elf64_Verneed uses the following struct definition.
|
|
- vn_version: Version of structure. This value is currently set to 1 (
0x0001
). - vn_cnt: Number of associated verneed array entries, one in this case (
0x0001
). - vn_file: Offset in .dynstr section, pointing to libc.so.6 (
0x00000029
). - vn_aux: Offset to a corresponding entry in the vernaux array, first element in this case (
0x00000001
). - vn_next: Offset to the next verneed entry, in this scenario there are no more elements in the array (
0x00000000
).
It is optionally followed by an array of Elf64_Vernaux structures.
|
|
- vna_hash: Dependency name hash value (
0x751a6909
). - vna_flags: Dependency information flag bitmask (
0x0000
). - vna_other: Object file version identifier used in the .gnu.version symbol version array, in this case it references all the 3 symbols mentioned in .gnu.version (
0x0200
). However, if bit number 15 is set, the object cannot be used and the static linker will ignore the symbol’s presence in the object. - vna_name: Offset to the dependency name string in the section header, pointing to GLIBC_2.2.5 (
0x00000033
). - vna_next: Offset to the next vernaux entry, once again there are no more entries (
0x00000000
).
Again you can check the raw contents below.
00000000: 0100 0100 2900 0000 1000 0000 0000 0000 ....)...........
00000010: 751a 6909 0000 0200 3300 0000 0000 0000 u.i.....3.......
.interp
This section is used to specify the interpreter, also know as dynamic linker, we can check that out reading ld.so
man page:
The dynamic linker can be run either indirectly by running some
dynamically linked program or shared object (in which case no
command-line options to the dynamic linker can be passed and, in
the ELF case, the dynamic linker which is stored in the .interp
section of the program is executed) or directly by running:
/lib/ld-linux.so.* [OPTIONS] [PROGRAM [ARGUMENTS]]
Additionally from linux kernel load_elf_binary
function we know that if such segment is found then it would use it’s content as the interpreter:
|
|
In this scenario it is using /lib64/ld-linux-x86-64.so.2
.
00000000: 2f6c 6962 3634 2f6c 642d 6c69 6e75 782d /lib64/ld-linux-
00000010: 7838 362d 3634 2e73 6f2e 3200 x86-64.so.2.
.shstrtab
It contains a string table with section names. Used by ELF header in e_shstrndx field which holds the index.
00000000: 002e 7379 6d74 6162 002e 7374 7274 6162 ..symtab..strtab
00000010: 002e 7368 7374 7274 6162 002e 696e 7465 ..shstrtab..inte
00000020: 7270 002e 6e6f 7465 2e67 6e75 2e62 7569 rp..note.gnu.bui
00000030: 6c64 2d69 6400 2e6e 6f74 652e 4142 492d ld-id..note.ABI-
00000040: 7461 6700 2e67 6e75 2e68 6173 6800 2e64 tag..gnu.hash..d
00000050: 796e 7379 6d00 2e64 796e 7374 7200 2e67 ynsym..dynstr..g
00000060: 6e75 2e76 6572 7369 6f6e 002e 676e 752e nu.version..gnu.
00000070: 7665 7273 696f 6e5f 7200 2e72 656c 612e version_r..rela.
00000080: 6479 6e00 2e72 656c 612e 706c 7400 2e69 dyn..rela.plt..i
00000090: 6e69 7400 2e70 6c74 2e67 6f74 002e 7465 nit..plt.got..te
000000a0: 7874 002e 6669 6e69 002e 726f 6461 7461 xt..fini..rodata
000000b0: 002e 6568 5f66 7261 6d65 5f68 6472 002e ..eh_frame_hdr..
000000c0: 6568 5f66 7261 6d65 002e 696e 6974 5f61 eh_frame..init_a
000000d0: 7272 6179 002e 6669 6e69 5f61 7272 6179 rray..fini_array
000000e0: 002e 6479 6e61 6d69 6300 2e67 6f74 2e70 ..dynamic..got.p
000000f0: 6c74 002e 6461 7461 002e 6273 7300 2e63 lt..data..bss..c
00000100: 6f6d 6d65 6e74 00 omment.
symbols
ELF files are full of things we need to keep track of for later access: Names, addresses, sizes, and intended purpose. Without this information, an ELF file would not be very useful. We would have no way to make sense of the impenetrable mass of octal or hexidecimal numbers.
Consider: When you write a program in any language above direct machine code, you give symbolic names to functions and data. The compiler turns these things into code. At the machine level, they are known only by their address (offset within the file) and their size. There are no names in this machine code. How then, can a linker combine multiple object files, or a symbolic debugger know what name to use for a given address? How do we make sense of these files?
Symbols are the way we manage this information. Compilers generate symbol information along with code. Linkers manipulate symbols, reading them in, matching them up, and writing them out. Almost everything a linker does is driven by symbols. Finally, debuggers use them to figure out what they are looking at and to provide you with a human readable view of that information.
The structure is defined in elf header.
|
|
.dynstr
Strings needed for dynamic linking, most commonly the strings that represent the names associated with symbol table entries.
00000000: 0070 7269 6e74 6600 5f5f 6378 615f 6669 .printf.__cxa_fi
00000010: 6e61 6c69 7a65 005f 5f6c 6962 635f 7374 nalize.__libc_st
00000020: 6172 745f 6d61 696e 006c 6962 632e 736f art_main.libc.so
00000030: 2e36 0047 4c49 4243 5f32 2e32 2e35 005f .6.GLIBC_2.2.5._
00000040: 4954 4d5f 6465 7265 6769 7374 6572 544d ITM_deregisterTM
00000050: 436c 6f6e 6554 6162 6c65 005f 5f67 6d6f CloneTable.__gmo
00000060: 6e5f 7374 6172 745f 5f00 5f49 544d 5f72 n_start__._ITM_r
00000070: 6567 6973 7465 7254 4d43 6c6f 6e65 5461 egisterTMCloneTa
00000080: 626c 6500 ble.
.strtab
Similarly to .dynstr it stores all symbols needed for .symtab section.
00000000: 0063 7274 7374 7566 662e 6300 6465 7265 .crtstuff.c.dere
00000010: 6769 7374 6572 5f74 6d5f 636c 6f6e 6573 gister_tm_clones
00000020: 005f 5f64 6f5f 676c 6f62 616c 5f64 746f .__do_global_dto
00000030: 7273 5f61 7578 0063 6f6d 706c 6574 6564 rs_aux.completed
00000040: 2e30 005f 5f64 6f5f 676c 6f62 616c 5f64 .0.__do_global_d
00000050: 746f 7273 5f61 7578 5f66 696e 695f 6172 tors_aux_fini_ar
00000060: 7261 795f 656e 7472 7900 6672 616d 655f ray_entry.frame_
00000070: 6475 6d6d 7900 5f5f 6672 616d 655f 6475 dummy.__frame_du
00000080: 6d6d 795f 696e 6974 5f61 7272 6179 5f65 mmy_init_array_e
00000090: 6e74 7279 0068 656c 6c6f 2e63 005f 5f46 ntry.hello.c.__F
000000a0: 5241 4d45 5f45 4e44 5f5f 005f 5f69 6e69 RAME_END__.__ini
000000b0: 745f 6172 7261 795f 656e 6400 5f44 594e t_array_end._DYN
000000c0: 414d 4943 005f 5f69 6e69 745f 6172 7261 AMIC.__init_arra
000000d0: 795f 7374 6172 7400 5f5f 474e 555f 4548 y_start.__GNU_EH
000000e0: 5f46 5241 4d45 5f48 4452 005f 474c 4f42 _FRAME_HDR._GLOB
000000f0: 414c 5f4f 4646 5345 545f 5441 424c 455f AL_OFFSET_TABLE_
00000100: 005f 5f6c 6962 635f 6373 755f 6669 6e69 .__libc_csu_fini
00000110: 005f 4954 4d5f 6465 7265 6769 7374 6572 ._ITM_deregister
00000120: 544d 436c 6f6e 6554 6162 6c65 005f 6564 TMCloneTable._ed
00000130: 6174 6100 7072 696e 7466 4047 4c49 4243 ata.printf@GLIBC
00000140: 5f32 2e32 2e35 005f 5f6c 6962 635f 7374 _2.2.5.__libc_st
00000150: 6172 745f 6d61 696e 4047 4c49 4243 5f32 art_main@GLIBC_2
00000160: 2e32 2e35 005f 5f64 6174 615f 7374 6172 .2.5.__data_star
00000170: 7400 5f5f 676d 6f6e 5f73 7461 7274 5f5f t.__gmon_start__
00000180: 005f 5f64 736f 5f68 616e 646c 6500 5f49 .__dso_handle._I
00000190: 4f5f 7374 6469 6e5f 7573 6564 005f 5f6c O_stdin_used.__l
000001a0: 6962 635f 6373 755f 696e 6974 005f 5f62 ibc_csu_init.__b
000001b0: 7373 5f73 7461 7274 006d 6169 6e00 5f5f ss_start.main.__
000001c0: 544d 435f 454e 445f 5f00 5f49 544d 5f72 TMC_END__._ITM_r
000001d0: 6567 6973 7465 7254 4d43 6c6f 6e65 5461 egisterTMCloneTa
000001e0: 626c 6500 5f5f 6378 615f 6669 6e61 6c69 ble.__cxa_finali
000001f0: 7a65 4047 4c49 4243 5f32 2e32 2e35 00 ze@GLIBC_2.2.5.
.dynsym
The dynsym is a smaller version of the symtab that only contains global symbols. The information found in the dynsym is therefore also found in the symtab, while the reverse is not necessarily true. This is done so only needed symbols are kept in memory and make other symbols non allocable.
The following code block displays the content of .dynsym section.
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 3f00 0000 2000 0000 ........?... ...
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0100 0000 1200 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 1700 0000 1200 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 5b00 0000 2000 0000 0000 0000 0000 0000 [... ...........
00000070: 0000 0000 0000 0000 6a00 0000 2000 0000 ........j... ...
00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000090: 0800 0000 2200 0000 0000 0000 0000 0000 ...."...........
000000a0: 0000 0000 0000 0000 ........
Each symbol are represented using elf64_sym
struct:
typedef struct elf64_sym {
Elf64_Word st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */
Elf64_Half st_shndx; /* Associated section index */
Elf64_Addr st_value; /* Value of the symbol */
Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym;
Each symbol is 24 bytes large, meaning that there are 7 symbols used at run time generated by GCC.
st_name | st_info | st_other | st_shndx | st_value | st_size |
---|---|---|---|---|---|
0 | 0 | 00 | 0000 | 0 | 0 |
3f00 0000 | 20 | 00 | 0000 | 0 | 0 |
0100 0000 | 12 | 00 | 0000 | 0 | 0 |
1700 0000 | 12 | 00 | 0000 | 0 | 0 |
5b00 0000 | 20 | 00 | 0000 | 0 | 0 |
6A00 0000 | 20 | 00 | 0000 | 0 | 0 |
0800 0000 | 22 | 00 | 0000 | 0 | 0 |
Using ELF32_ST_BIND and ELF32_ST_TYPE from elf header together with next section .dynstr we can analyze in more detail the attributes of each symbol. Ignoring the rest of fields because they are just filled with zeroes.
st_name | st_bind | st_type |
---|---|---|
_ITM_deregisterTMCloneTable | STB_WEAK | STT_NOTYPE |
printf | STB_GLOBAL | STT_FUNC |
__libc_start_main | STB_GLOBAL | STT_FUNC |
__gmon_start__ | STB_WEAK | STT_NOTYPE |
_ITM_registerTMCloneTable | STB_WEAK | STT_NOTYPE |
__cxa_finalize | STB_WEAK | STT_FUNC |
In this case it uses two different type of binds.
- STB_GLOBAL: These symbols are visible to all object files being combined. One file’s definition of a global symbol will satisfy another file’s undefined reference to the same global symbol.
- STB_WEAK: Weak symbols. These symbols resemble global symbols, but their definitions have lower precedence.
It also uses two types:
- STT_NOTYPE: Used when we don’t know what a symbol is, or to indicate the absence of a symbol.
- STT_FUNC: A function, or other executable code.
Besides libc it also uses libitm and some initializing and termination functions.
.symtab
As previously explained it contains all symbols that are needed by linkers, debuggers, and other such tools, but which are not needed by the running program.
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0300 0100 ................
00000020: a802 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0300 0200 c402 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0300 0300 ................
00000050: e802 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 0300 0400 0803 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0300 0500 ................
00000080: 3003 0000 0000 0000 0000 0000 0000 0000 0...............
00000090: 0000 0000 0300 0600 d803 0000 0000 0000 ................
000000a0: 0000 0000 0000 0000 0000 0000 0300 0700 ................
000000b0: 5c04 0000 0000 0000 0000 0000 0000 0000 \...............
000000c0: 0000 0000 0300 0800 7004 0000 0000 0000 ........p.......
000000d0: 0000 0000 0000 0000 0000 0000 0300 0900 ................
000000e0: 9004 0000 0000 0000 0000 0000 0000 0000 ................
000000f0: 0000 0000 0300 0a00 5005 0000 0000 0000 ........P.......
00000100: 0000 0000 0000 0000 0000 0000 0300 0b00 ................
00000110: 0010 0000 0000 0000 0000 0000 0000 0000 ................
00000120: 0000 0000 0300 0c00 2010 0000 0000 0000 ........ .......
00000130: 0000 0000 0000 0000 0000 0000 0300 0d00 ................
00000140: 4010 0000 0000 0000 0000 0000 0000 0000 @...............
00000150: 0000 0000 0300 0e00 5010 0000 0000 0000 ........P.......
00000160: 0000 0000 0000 0000 0000 0000 0300 0f00 ................
00000170: c411 0000 0000 0000 0000 0000 0000 0000 ................
00000180: 0000 0000 0300 1000 0020 0000 0000 0000 ......... ......
00000190: 0000 0000 0000 0000 0000 0000 0300 1100 ................
000001a0: 1420 0000 0000 0000 0000 0000 0000 0000 . ..............
000001b0: 0000 0000 0300 1200 5020 0000 0000 0000 ........P ......
000001c0: 0000 0000 0000 0000 0000 0000 0300 1300 ................
000001d0: e83d 0000 0000 0000 0000 0000 0000 0000 .=..............
000001e0: 0000 0000 0300 1400 f03d 0000 0000 0000 .........=......
000001f0: 0000 0000 0000 0000 0000 0000 0300 1500 ................
00000200: f83d 0000 0000 0000 0000 0000 0000 0000 .=..............
00000210: 0000 0000 0300 1600 d83f 0000 0000 0000 .........?......
00000220: 0000 0000 0000 0000 0000 0000 0300 1700 ................
00000230: 0040 0000 0000 0000 0000 0000 0000 0000 .@..............
00000240: 0000 0000 0300 1800 2040 0000 0000 0000 ........ @......
00000250: 0000 0000 0000 0000 0000 0000 0300 1900 ................
00000260: 3040 0000 0000 0000 0000 0000 0000 0000 0@..............
00000270: 0000 0000 0300 1a00 0000 0000 0000 0000 ................
00000280: 0000 0000 0000 0000 0100 0000 0400 f1ff ................
00000290: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000002a0: 0c00 0000 0200 0e00 8010 0000 0000 0000 ................
000002b0: 0000 0000 0000 0000 0e00 0000 0200 0e00 ................
000002c0: b010 0000 0000 0000 0000 0000 0000 0000 ................
000002d0: 2100 0000 0200 0e00 f010 0000 0000 0000 !...............
000002e0: 0000 0000 0000 0000 3700 0000 0100 1900 ........7.......
000002f0: 3040 0000 0000 0000 0100 0000 0000 0000 0@..............
00000300: 4300 0000 0100 1400 f03d 0000 0000 0000 C........=......
00000310: 0000 0000 0000 0000 6a00 0000 0200 0e00 ........j.......
00000320: 3011 0000 0000 0000 0000 0000 0000 0000 0...............
00000330: 7600 0000 0100 1300 e83d 0000 0000 0000 v........=......
00000340: 0000 0000 0000 0000 9500 0000 0400 f1ff ................
00000350: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000360: 0100 0000 0400 f1ff 0000 0000 0000 0000 ................
00000370: 0000 0000 0000 0000 9d00 0000 0100 1200 ................
00000380: 5421 0000 0000 0000 0000 0000 0000 0000 T!..............
00000390: 0000 0000 0400 f1ff 0000 0000 0000 0000 ................
000003a0: 0000 0000 0000 0000 ab00 0000 0000 1300 ................
000003b0: f03d 0000 0000 0000 0000 0000 0000 0000 .=..............
000003c0: bc00 0000 0100 1500 f83d 0000 0000 0000 .........=......
000003d0: 0000 0000 0000 0000 c500 0000 0000 1300 ................
000003e0: e83d 0000 0000 0000 0000 0000 0000 0000 .=..............
000003f0: d800 0000 0000 1100 1420 0000 0000 0000 ......... ......
00000400: 0000 0000 0000 0000 eb00 0000 0100 1700 ................
00000410: 0040 0000 0000 0000 0000 0000 0000 0000 .@..............
00000420: a701 0000 0200 0b00 0010 0000 0000 0000 ................
00000430: 0000 0000 0000 0000 0101 0000 1200 0e00 ................
00000440: c011 0000 0000 0000 0100 0000 0000 0000 ................
00000450: 1101 0000 2000 0000 0000 0000 0000 0000 .... ...........
00000460: 0000 0000 0000 0000 6701 0000 2000 1800 ........g... ...
00000470: 2040 0000 0000 0000 0000 0000 0000 0000 @..............
00000480: 2d01 0000 1000 1800 3040 0000 0000 0000 -.......0@......
00000490: 0000 0000 0000 0000 0b01 0000 1202 0f00 ................
000004a0: c411 0000 0000 0000 0000 0000 0000 0000 ................
000004b0: 3401 0000 1200 0000 0000 0000 0000 0000 4...............
000004c0: 0000 0000 0000 0000 4701 0000 1200 0000 ........G.......
000004d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000004e0: 6501 0000 1000 1800 2040 0000 0000 0000 e....... @......
000004f0: 0000 0000 0000 0000 7201 0000 2000 0000 ........r... ...
00000500: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000510: 8101 0000 1102 1800 2840 0000 0000 0000 ........(@......
00000520: 0000 0000 0000 0000 8e01 0000 1100 1000 ................
00000530: 0020 0000 0000 0000 0400 0000 0000 0000 . ..............
00000540: 9d01 0000 1200 0e00 6011 0000 0000 0000 ........`.......
00000550: 5d00 0000 0000 0000 b700 0000 1000 1900 ]...............
00000560: 3840 0000 0000 0000 0000 0000 0000 0000 8@..............
00000570: 6b01 0000 1200 0e00 5010 0000 0000 0000 k.......P.......
00000580: 2b00 0000 0000 0000 ad01 0000 1000 1900 +...............
00000590: 3040 0000 0000 0000 0000 0000 0000 0000 0@..............
000005a0: b901 0000 1200 0e00 3511 0000 0000 0000 ........5.......
000005b0: 2700 0000 0000 0000 be01 0000 1102 1800 '...............
000005c0: 3040 0000 0000 0000 0000 0000 0000 0000 0@..............
000005d0: ca01 0000 2000 0000 0000 0000 0000 0000 .... ...........
000005e0: 0000 0000 0000 0000 e401 0000 2200 0000 ............"...
000005f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
There are new types like STT_SECTION or STB_LOCAL bind.
Symbol table '.symtab' contains 64 entries:
Num: Valor Tam Tipo Unión Vis Nombre Ind
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000000002a8 0 SECTION LOCAL DEFAULT 1
2: 00000000000002c4 0 SECTION LOCAL DEFAULT 2
3: 00000000000002e8 0 SECTION LOCAL DEFAULT 3
4: 0000000000000308 0 SECTION LOCAL DEFAULT 4
5: 0000000000000330 0 SECTION LOCAL DEFAULT 5
6: 00000000000003d8 0 SECTION LOCAL DEFAULT 6
7: 000000000000045c 0 SECTION LOCAL DEFAULT 7
8: 0000000000000470 0 SECTION LOCAL DEFAULT 8
9: 0000000000000490 0 SECTION LOCAL DEFAULT 9
10: 0000000000000550 0 SECTION LOCAL DEFAULT 10
11: 0000000000001000 0 SECTION LOCAL DEFAULT 11
12: 0000000000001020 0 SECTION LOCAL DEFAULT 12
13: 0000000000001040 0 SECTION LOCAL DEFAULT 13
14: 0000000000001050 0 SECTION LOCAL DEFAULT 14
15: 00000000000011c4 0 SECTION LOCAL DEFAULT 15
16: 0000000000002000 0 SECTION LOCAL DEFAULT 16
17: 0000000000002014 0 SECTION LOCAL DEFAULT 17
18: 0000000000002050 0 SECTION LOCAL DEFAULT 18
19: 0000000000003de8 0 SECTION LOCAL DEFAULT 19
20: 0000000000003df0 0 SECTION LOCAL DEFAULT 20
21: 0000000000003df8 0 SECTION LOCAL DEFAULT 21
22: 0000000000003fd8 0 SECTION LOCAL DEFAULT 22
23: 0000000000004000 0 SECTION LOCAL DEFAULT 23
24: 0000000000004020 0 SECTION LOCAL DEFAULT 24
25: 0000000000004030 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
28: 0000000000001080 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
29: 00000000000010b0 0 FUNC LOCAL DEFAULT 14 register_tm_clones
30: 00000000000010f0 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
31: 0000000000004030 1 OBJECT LOCAL DEFAULT 25 completed.0
32: 0000000000003df0 0 OBJECT LOCAL DEFAULT 20 __do_global_dtor[...]
33: 0000000000001130 0 FUNC LOCAL DEFAULT 14 frame_dummy
34: 0000000000003de8 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_in[...]
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS hello.c
36: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
37: 0000000000002154 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
38: 0000000000000000 0 FILE LOCAL DEFAULT ABS
39: 0000000000003df0 0 NOTYPE LOCAL DEFAULT 19 __init_array_end
40: 0000000000003df8 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
41: 0000000000003de8 0 NOTYPE LOCAL DEFAULT 19 __init_array_start
42: 0000000000002014 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
43: 0000000000004000 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
44: 0000000000001000 0 FUNC LOCAL DEFAULT 11 _init
45: 00000000000011c0 1 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
46: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
47: 0000000000004020 0 NOTYPE WEAK DEFAULT 24 data_start
48: 0000000000004030 0 NOTYPE GLOBAL DEFAULT 24 _edata
49: 00000000000011c4 0 FUNC GLOBAL HIDDEN 15 _fini
50: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_mai[...]
52: 0000000000004020 0 NOTYPE GLOBAL DEFAULT 24 __data_start
53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
54: 0000000000004028 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
55: 0000000000002000 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
56: 0000000000001160 93 FUNC GLOBAL DEFAULT 14 __libc_csu_init
57: 0000000000004038 0 NOTYPE GLOBAL DEFAULT 25 _end
58: 0000000000001050 43 FUNC GLOBAL DEFAULT 14 _start
59: 0000000000004030 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
60: 0000000000001135 39 FUNC GLOBAL DEFAULT 14 main
61: 0000000000004030 0 OBJECT GLOBAL HIDDEN 24 __TMC_END__
62: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMC[...]
63: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@G[...]
relocations
Relocations are essential for creating position-independent code (PIC) or shared libraries, which can be loaded at arbitrary memory locations. They also allow for dynamic linking, where the linking of libraries is done at runtime, rather than at compile-time, allowing for greater flexibility and modularity in software development.
.rela.dyn
For dynamic binaries, this relocation table holds information of variables which must be relocated upon loading.
00000000: e83d 0000 0000 0000 0800 0000 0000 0000 .=..............
00000010: 3011 0000 0000 0000 f03d 0000 0000 0000 0........=......
00000020: 0800 0000 0000 0000 f010 0000 0000 0000 ................
00000030: 2840 0000 0000 0000 0800 0000 0000 0000 (@..............
00000040: 2840 0000 0000 0000 d83f 0000 0000 0000 (@.......?......
00000050: 0600 0000 0100 0000 0000 0000 0000 0000 ................
00000060: e03f 0000 0000 0000 0600 0000 0300 0000 .?..............
00000070: 0000 0000 0000 0000 e83f 0000 0000 0000 .........?......
00000080: 0600 0000 0400 0000 0000 0000 0000 0000 ................
00000090: f03f 0000 0000 0000 0600 0000 0500 0000 .?..............
000000a0: 0000 0000 0000 0000 f83f 0000 0000 0000 .........?......
000000b0: 0600 0000 0600 0000 0000 0000 0000 0000 ................
Each entry in this table is a struct Elf64_Rela, holding information to handle dynamic relocations.
|
|
For this binary there are only two types of dynamic relocations generated.
La sección de reubicación '.rela.dyn' at offset 0x490 contains 8 entries:
Desplaz Info Tipo Val. Símbolo Nom. Símbolo + Adend
000000003de8 000000000008 R_X86_64_RELATIVE 1130
000000003df0 000000000008 R_X86_64_RELATIVE 10f0
000000004028 000000000008 R_X86_64_RELATIVE 4028
000000003fd8 000100000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTM[...] + 0
000000003fe0 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
000000003fe8 000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000003ff0 000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCl[...] + 0
000000003ff8 000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0
Relative relocations
Identified by R_X86_64_RELATIVE type, they adjust by program base applying the following formula:
|
|
Remember that it applies the relocations at runtime so we need to execute it in order to prove it.
Below there is the virtual memory map for the process, so we know that the base address is 0x00555555554000
:
[ Legend: Code | Heap | Stack ]
Start End Offset Perm Path
0x00555555554000 0x00555555555000 0x00000000000000 r-- /home/itasahobby/Documentos/a.out
0x00555555555000 0x00555555556000 0x00000000001000 r-x /home/itasahobby/Documentos/a.out
0x00555555556000 0x00555555557000 0x00000000002000 r-- /home/itasahobby/Documentos/a.out
0x00555555557000 0x00555555558000 0x00000000002000 r-- /home/itasahobby/Documentos/a.out
0x00555555558000 0x00555555559000 0x00000000003000 rw- /home/itasahobby/Documentos/a.out
0x007ffff7ddd000 0x007ffff7dff000 0x00000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x007ffff7dff000 0x007ffff7f59000 0x00000000022000 r-x /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x007ffff7f59000 0x007ffff7fa8000 0x0000000017c000 r-- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x007ffff7fa8000 0x007ffff7fac000 0x000000001ca000 r-- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x007ffff7fac000 0x007ffff7fae000 0x000000001ce000 rw- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x007ffff7fae000 0x007ffff7fb4000 0x00000000000000 rw-
0x007ffff7fcc000 0x007ffff7fd0000 0x00000000000000 r-- [vvar]
0x007ffff7fd0000 0x007ffff7fd2000 0x00000000000000 r-x [vdso]
0x007ffff7fd2000 0x007ffff7fd3000 0x00000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x007ffff7fd3000 0x007ffff7ff3000 0x00000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x007ffff7ff3000 0x007ffff7ffb000 0x00000000021000 r-- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x007ffff7ffc000 0x007ffff7ffd000 0x00000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x007ffff7ffd000 0x007ffff7ffe000 0x0000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x007ffff7ffe000 0x007ffff7fff000 0x00000000000000 rw-
0x007ffffffde000 0x007ffffffff000 0x00000000000000 rw- [stack]
So at offset 0x000000003de8
in the elf (which corresponds to .init_array) the value should get patched with 0x00555555554000
+ 0x1130
:
x/1x 0x0000555555554000+0x000000003de8
0x555555557de8: 0x55555130
Global data
Identified by R_X86_64_GLOB_DAT type, it relocates with the value of the global symbol.
print *__libc_start_main
$3 = {int (int (*)(int, char **, char **), int, char **, int (*)(int, char **, char **), void (*)(void), void (*)(void), void *)} 0x7ffff7e00c20 <__libc_start_main>
x/2x 0x555555554000 + 0x3FE0
0x555555557fe0: 0xf7e00c20 0x00007fff
.rela.plt
This relocation table is similar to the one in .rela.dyn section; the difference is this one is for functions, not variables.
The relocation type of entries in this table is R_386_JMP_SLOT or R_X86_64_JUMP_SLOT and the “offset” refers to memory addresses which are inside .got.plt section.
Simply put, this table holds information to relocate entries in .got.plt section.
00000000: 1840 0000 0000 0000 0700 0000 0200 0000 .@..............
00000010: 0000 0000 0000 0000 ........
r_offset | r_info | r_addend |
---|---|---|
1840 0000 0000 0000 | 0700 0000 0200 0000 | 0000 0000 0000 0000 |
La sección de reubicación '.rela.plt' at offset 0x550 contains 1 entry:
Desplaz Info Tipo Val. Símbolo Nom. Símbolo + Adend
000000004018 000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
.got
The .got section in an ELF file stands for “Global Offset Table”. It is used to store addresses of global symbols (functions or variables) that are referenced by the executable or shared library.
When an ELF binary is loaded into memory, the addresses stored in the .got section are typically resolved and updated with the actual memory addresses of the symbols. This allows the binary to call functions or access data defined in other shared libraries or object files.
Is usually read-write because the addresses it contains need to be updated at runtime. However, some implementations may mark it as read-only after initialization for security reasons.
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 ........
On runtime we can see how one of the pointers resolves to __libc_start_main
.
x/10x 0x555555554000 + 0x0000000000003fd8
0x555555557fd8: 0x00000000 0x00000000 0xf7e00c20 0x00007fff
0x555555557fe8: 0x00000000 0x00000000 0x00000000 0x00000000
0x555555557ff8: 0xf7e18a00 0x00007fff
gef➤ dereference -l 1 0x00007ffff7e00c20
0x007ffff7e00c20│+0x0000: <__libc_start_main+0> push r15
.plt
The .plt section consists of a series of entries, each of which corresponds to a dynamically linked function used by the executable or shared library. Each entry in the PLT contains machine code that performs the dynamic symbol lookup and function call.
In summary, is a small piece of code that acts as a trampoline to dynamically linked functions, allowing for lazy binding of dynamic symbols and improving the startup time and memory usage of the executable or shared library.
00000000: ff35 e22f 0000 ff25 e42f 0000 0f1f 4000 .5./...%./....@.
00000010: ff25 e22f 0000 6800 0000 00e9 e0ff ffff .%./..h.........
We can disassembly the content and check how it holds jmp instructions.
0: ff 35 e2 2f 00 00 push QWORD PTR [rip+0x2fe2] # 0x2fe8
6: ff 25 e4 2f 00 00 jmp QWORD PTR [rip+0x2fe4] # 0x2ff0
c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
10: ff 25 e2 2f 00 00 jmp QWORD PTR [rip+0x2fe2] # 0x2ff8
16: 68 00 00 00 00 push 0x0
1b: e9 e0 ff ff ff jmp 0x0
If we test it on runtime we see how it jumps to .got.plt:
x/6i 0x0000555555554000 + 0x0000000000001020
0x555555555020: push QWORD PTR [rip+0x2fe2] # 0x555555558008
0x555555555026: jmp QWORD PTR [rip+0x2fe4] # 0x555555558010
0x55555555502c: nop DWORD PTR [rax+0x0]
0x555555555030 <printf@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x555555558018 <printf@got.plt>
0x555555555036 <printf@plt+6>: push 0x0
0x55555555503b <printf@plt+11>: jmp 0x555555555020
.got.plt
The .got.plt section in an ELF file is a variant of the “.got” section that is used specifically for dynamically linked executables or shared libraries that use the PLT (Procedure Linkage Table) mechanism for resolving function calls at runtime.
In the PLT-based dynamic linking, is used to store the addresses of the PLT entries for each dynamically linked function that is used by the executable or shared library. The PLT entries themselves are used to resolve the actual addresses of the functions at runtime, and is updated with the resolved addresses once they have been resolved.
The use of the PLT mechanism allows for lazy binding of dynamic symbols, meaning that the symbols are not resolved until the first time they are used, which can improve the startup time and reduce memory usage of the executable or shared library.
To sum up is used to store the addresses of the PLT entries for dynamically linked functions, and is updated at runtime as the PLT entries are resolved.
You can see the contents of the section before runtime.
00000000: f83d 0000 0000 0000 0000 0000 0000 0000 .=..............
00000010: 0000 0000 0000 0000 3610 0000 0000 0000 ........6.......
So before printf
gets called if looks like the following.
x/8x 0x0000555555554000 + 0000000000004000
0x555555558000: 0x00003df8 0x00000000 0xf7ffe180 0x00007fff
0x555555558010: 0xf7fe8610 0x00007fff 0x55555036 0x00005555
Updating the address to 0x00007ffff7e30cf0
which points to the shared library where printf is located:
dereference 0x00007ffff7e30cf0
0x007ffff7e30cf0│+0x0000: <printf+0> sub rsp, 0xd8
0x007ffff7e30cf8│+0x0008: <printf+8> mov edx, edi
0x007ffff7e30d00│+0x0010: <printf+16> mov DWORD PTR [rsp+0x30], edx
0x007ffff7e30d08│+0x0018: <printf+24> cmp BYTE PTR [rcx+rcx*4+0x44], cl
0x007ffff7e30d10│+0x0020: <printf+32> rex.WR and al, 0x48
0x007ffff7e30d18│+0x0028: <printf+40> sub DWORD PTR [rsp+0x50], eax
0x007ffff7e30d20│+0x0030: <printf+48> (bad)
0x007ffff7e30d28│+0x0038: <printf+56> pushf
0x007ffff7e30d30│+0x0040: <printf+64> movs BYTE PTR es:[rdi], BYTE PTR ds:[rsi]
0x007ffff7e30d38│+0x0048: <printf+72> lods al, BYTE PTR ds:[rsi]
.plt.got
In ELF binaries that use the .plt.got section, the PLT entries are not directly responsible for resolving the addresses of the dynamic functions. Instead, they use a stub function. When a dynamic function is called through a PLT entry, the stub function first checks the corresponding GOT entry (which is stored in the .got.plt section) to see if the address of the function has already been resolved. If it has, the stub function simply jumps to the resolved address. If not, the stub function jumps to the dynamic linker to resolve the address, updates the corresponding GOT entry with the resolved address, and then jumps to the resolved address.
It allows for faster function calls, as the PLT entries do not need to perform the GOT lookup on every call, but instead rely on the stub function to perform the lookup and cache the result in the GOT.
In summary, the “.plt.got” section is used to speed up function calls in dynamically linked ELF binaries by providing a stub function that caches the resolved addresses of dynamic functions in the GOT.
00000000: ff25 b22f 0000 6690 .%./..f.
.dynamic
When a dynamically linked binary is loaded into memory, the dynamic linker reads the “.dynamic” section to determine the locations of shared libraries, the locations of the symbol tables, and other information needed to properly link the binary at runtime.
The .dynamic section is usually read-only, as it is not updated during the lifetime of the program. However, some entries may be updated by the dynamic linker during the loading process.
In summary,is a table of entries that specify various dynamic properties of the binary, and is used by the dynamic linker to properly link the binary with shared libraries at runtime.
00000000: 0100 0000 0000 0000 2900 0000 0000 0000 ........).......
00000010: 0c00 0000 0000 0000 0010 0000 0000 0000 ................
00000020: 0d00 0000 0000 0000 c411 0000 0000 0000 ................
00000030: 1900 0000 0000 0000 e83d 0000 0000 0000 .........=......
00000040: 1b00 0000 0000 0000 0800 0000 0000 0000 ................
00000050: 1a00 0000 0000 0000 f03d 0000 0000 0000 .........=......
00000060: 1c00 0000 0000 0000 0800 0000 0000 0000 ................
00000070: f5fe ff6f 0000 0000 0803 0000 0000 0000 ...o............
00000080: 0500 0000 0000 0000 d803 0000 0000 0000 ................
00000090: 0600 0000 0000 0000 3003 0000 0000 0000 ........0.......
000000a0: 0a00 0000 0000 0000 8400 0000 0000 0000 ................
000000b0: 0b00 0000 0000 0000 1800 0000 0000 0000 ................
000000c0: 1500 0000 0000 0000 0000 0000 0000 0000 ................
000000d0: 0300 0000 0000 0000 0040 0000 0000 0000 .........@......
000000e0: 0200 0000 0000 0000 1800 0000 0000 0000 ................
000000f0: 1400 0000 0000 0000 0700 0000 0000 0000 ................
00000100: 1700 0000 0000 0000 5005 0000 0000 0000 ........P.......
00000110: 0700 0000 0000 0000 9004 0000 0000 0000 ................
00000120: 0800 0000 0000 0000 c000 0000 0000 0000 ................
00000130: 0900 0000 0000 0000 1800 0000 0000 0000 ................
00000140: fbff ff6f 0000 0000 0000 0008 0000 0000 ...o............
00000150: feff ff6f 0000 0000 7004 0000 0000 0000 ...o....p.......
00000160: ffff ff6f 0000 0000 0100 0000 0000 0000 ...o............
00000170: f0ff ff6f 0000 0000 5c04 0000 0000 0000 ...o....\.......
00000180: f9ff ff6f 0000 0000 0300 0000 0000 0000 ...o............
00000190: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Below you can see that libc is marked as needed, together with other information needed to link the binary.
Dynamic section at offset 0x2df8 contains 26 entries:
Marca Tipo Nombre/Valor
0x0000000000000001 (NEEDED) Biblioteca compartida: [libc.so.6]
0x000000000000000c (INIT) 0x1000
0x000000000000000d (FINI) 0x11c4
0x0000000000000019 (INIT_ARRAY) 0x3de8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x3df0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x308
0x0000000000000005 (STRTAB) 0x3d8
0x0000000000000006 (SYMTAB) 0x330
0x000000000000000a (STRSZ) 132 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x4000
0x0000000000000002 (PLTRELSZ) 24 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x550
0x0000000000000007 (RELA) 0x490
0x0000000000000008 (RELASZ) 192 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffb (FLAGS_1) Opciones: PIE
0x000000006ffffffe (VERNEED) 0x470
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x45c
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0
initialization
The implementation is responsible for executing the initialization functions specified by DT_INIT, DT_INIT_ARRAY, and DT_PREINIT_ARRAY entries in the executable file and shared object files for a process, and the termination (or finalization) functions specified by DT_FINI and DT_FINI_ARRAY, as specified by the System V ABI. The user program plays no further part in executing the initialization and termination functions specified by these dynamic tags.
If an object contains both DT_INIT and DT_INIT_ARRAY entries, the function referenced by the DT_INIT entry is processed before those referenced by the DT_INIT_ARRAY entry for that object. If an object contains both DT_FINI and DT_FINI_ARRAY entries, the functions referenced by the DT_FINI_ARRAY entry are processed before the one referenced by the DT_FINI entry for that object. Additionally SHT_PREINIT_ARRAY get’s executed just before DT_INIT.
In this environment the libc is in charge of this task.
.init
This section holds executable instructions that contribute to the process initialization code. That is, when a program starts to run the system arranges to execute the code in this section before the main program entry point (called main in C programs).
00000000: 4883 ec08 488b 05dd 2f00 0048 85c0 7402 H...H.../..H..t.
00000010: ffd0 4883 c408 c3 ..H....
Using a disassembler we can check the corresponding instructions.
0: 48 83 ec 08 sub rsp,0x8
4: 48 8b 05 dd 2f 00 00 mov rax,QWORD PTR [rip+0x2fdd] # 0x2fe8
b: 48 85 c0 test rax,rax
e: 74 02 je 0x12
10: ff d0 call rax
12: 48 83 c4 08 add rsp,0x8
16: c3 ret
.fini
This section holds executable instructions that contribute to the process termination code. That is, when a program exits normally, the system arranges to execute the code in this section.
00000000: 4883 ec08 4883 c408 c3 H...H....
In this case it does nothing apparently.
0: 48 83 ec 08 sub rsp,0x8
4: 48 83 c4 08 add rsp,0x8
8: c3 ret
.init_array
This section contains an array of pointers to initialization functions.
00000000: 3011 0000 0000 0000 0.......
.fini_array
This section contains an array of pointers to termination functions.
00000000: f010 0000 0000 0000 ........
data
There are some special sections to store different type of information like variables or executable code.
.data
Contains the global variables and static variables that are initialized.
00000000: 0000 0000 0000 0000 2840 0000 0000 0000 ........(@......
.rodata
Behaves just like .data for read only data.
00000000: 0100 0200 4865 6c6c 6f20 576f 726c 6421 ....Hello World!
00000010: 00 .
.bss
Contains all global and static variables that do not have explicit initialization. By default, zero-initialized data is also put into this section. This section is of type NOBITS occupying no space in the file.
.text
The text segment defines a read-only executable loadable segment that accepts allocable, non-writable sections. This includes executable code, read-only data needed by the program, and read-only data produced by the link-editor for use by the runtime linker such as the dynamic symbol table.
00000000: 31ed 4989 d15e 4889 e248 83e4 f050 544c 1.I..^H..H...PTL
00000010: 8d05 5a01 0000 488d 0df3 0000 0048 8d3d ..Z...H......H.=
00000020: c100 0000 ff15 662f 0000 f40f 1f44 0000 ......f/.....D..
00000030: 488d 3da9 2f00 0048 8d05 a22f 0000 4839 H.=./..H.../..H9
00000040: f874 1548 8b05 3e2f 0000 4885 c074 09ff .t.H..>/..H..t..
00000050: e00f 1f80 0000 0000 c30f 1f80 0000 0000 ................
00000060: 488d 3d79 2f00 0048 8d35 722f 0000 4829 H.=y/..H.5r/..H)
00000070: fe48 89f0 48c1 ee3f 48c1 f803 4801 c648 .H..H..?H...H..H
00000080: d1fe 7414 488b 0515 2f00 0048 85c0 7408 ..t.H.../..H..t.
00000090: ffe0 660f 1f44 0000 c30f 1f80 0000 0000 ..f..D..........
000000a0: 803d 392f 0000 0075 2f55 4883 3df6 2e00 .=9/...u/UH.=...
000000b0: 0000 4889 e574 0c48 8b3d 1a2f 0000 e82d ..H..t.H.=./...-
000000c0: ffff ffe8 68ff ffff c605 112f 0000 015d ....h....../...]
000000d0: c30f 1f80 0000 0000 c30f 1f80 0000 0000 ................
000000e0: e97b ffff ff55 4889 e548 83ec 1089 7dfc .{...UH..H....}.
000000f0: 4889 75f0 488d 3db9 0e00 00b8 0000 0000 H.u.H.=.........
00000100: e8db feff ffb8 0000 0000 c9c3 0f1f 4000 ..............@.
00000110: 4157 4c8d 3d7f 2c00 0041 5649 89d6 4155 AWL.=.,..AVI..AU
00000120: 4989 f541 5441 89fc 5548 8d2d 702c 0000 I..ATA..UH.-p,..
00000130: 534c 29fd 4883 ec08 e873 feff ff48 c1fd SL).H....s...H..
00000140: 0374 1b31 db0f 1f00 4c89 f24c 89ee 4489 .t.1....L..L..D.
00000150: e741 ff14 df48 83c3 0148 39dd 75ea 4883 .A...H...H9.u.H.
00000160: c408 5b5d 415c 415d 415e 415f c30f 1f00 ..[]A\A]A^A_....
00000170: c3 .
The disassembly is shown below.
0: 31 ed xor ebp,ebp
2: 49 89 d1 mov r9,rdx
5: 5e pop rsi
6: 48 89 e2 mov rdx,rsp
9: 48 83 e4 f0 and rsp,0xfffffffffffffff0
d: 50 push rax
e: 54 push rsp
f: 4c 8d 05 5a 01 00 00 lea r8,[rip+0x15a] # 0x170
16: 48 8d 0d f3 00 00 00 lea rcx,[rip+0xf3] # 0x110
1d: 48 8d 3d c1 00 00 00 lea rdi,[rip+0xc1] # 0xe5
24: ff 15 66 2f 00 00 call QWORD PTR [rip+0x2f66] # 0x2f90
2a: f4 hlt
2b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
30: 48 8d 3d a9 2f 00 00 lea rdi,[rip+0x2fa9] # 0x2fe0
37: 48 8d 05 a2 2f 00 00 lea rax,[rip+0x2fa2] # 0x2fe0
3e: 48 39 f8 cmp rax,rdi
41: 74 15 je 0x58
43: 48 8b 05 3e 2f 00 00 mov rax,QWORD PTR [rip+0x2f3e] # 0x2f88
4a: 48 85 c0 test rax,rax
4d: 74 09 je 0x58
4f: ff e0 jmp rax
51: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
58: c3 ret
59: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
60: 48 8d 3d 79 2f 00 00 lea rdi,[rip+0x2f79] # 0x2fe0
67: 48 8d 35 72 2f 00 00 lea rsi,[rip+0x2f72] # 0x2fe0
6e: 48 29 fe sub rsi,rdi
71: 48 89 f0 mov rax,rsi
74: 48 c1 ee 3f shr rsi,0x3f
78: 48 c1 f8 03 sar rax,0x3
7c: 48 01 c6 add rsi,rax
7f: 48 d1 fe sar rsi,1
82: 74 14 je 0x98
84: 48 8b 05 15 2f 00 00 mov rax,QWORD PTR [rip+0x2f15] # 0x2fa0
8b: 48 85 c0 test rax,rax
8e: 74 08 je 0x98
90: ff e0 jmp rax
92: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
98: c3 ret
99: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
a0: 80 3d 39 2f 00 00 00 cmp BYTE PTR [rip+0x2f39],0x0 # 0x2fe0
a7: 75 2f jne 0xd8
a9: 55 push rbp
aa: 48 83 3d f6 2e 00 00 cmp QWORD PTR [rip+0x2ef6],0x0 # 0x2fa8
b1: 00
b2: 48 89 e5 mov rbp,rsp
b5: 74 0c je 0xc3
b7: 48 8b 3d 1a 2f 00 00 mov rdi,QWORD PTR [rip+0x2f1a] # 0x2fd8
be: e8 2d ff ff ff call 0xfffffffffffffff0
c3: e8 68 ff ff ff call 0x30
c8: c6 05 11 2f 00 00 01 mov BYTE PTR [rip+0x2f11],0x1 # 0x2fe0
cf: 5d pop rbp
d0: c3 ret
d1: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
d8: c3 ret
d9: 0f 1f 80 00 00 00 00 nop DWORD PTR [rax+0x0]
e0: e9 7b ff ff ff jmp 0x60
exception frames
In ELF binary, there are two sections to support exception handling routines that are predominately used by C++ applications: .eh_frame and .eh_frame_hdr.
.eh_frame_hdr
The .eh_frame_hdr section contains a binary search table of pointers to the .eh_frame records.
As shown in eh_frame_hdr struct it includes the following fields.
- version (unsigned byte): Version of the .eh_frame_hdr format. This value must be 1.
- eh_frame_ptr_enc (unsigned byte): The encoding format of the eh_frame_ptr field.
- fde_count_enc (unsigned byte): The encoding format of the fde_count field. A value of DW_EH_PE_omit indicates the binary search table is not present.
- table_enc (unsigned byte): The encoding format of the entries in the binary search table. A value of DW_EH_PE_omit indicates the binary search table is not present.
- eh_frame_ptr (encoded): The encoded value of the pointer to the start of the .eh_frame section.
- fde_count (encoded): The encoded value of the count of entries in the binary search table.
- binary search table: A binary search table containing fde_count entries. Each entry of the table consist of two encoded values, the initial location, and the address. The entries are sorted in an increasing order by the initial location value.
00000000: 011b 033b 3800 0000 0600 0000 0cf0 ffff ...;8...........
00000010: 8400 0000 2cf0 ffff ac00 0000 3cf0 ffff ....,.......<...
00000020: 5400 0000 21f1 ffff c400 0000 4cf1 ffff T...!.......L...
00000030: e400 0000 acf1 ffff 2c01 0000 ........,...
Each field has the following value.
- version: 0x01
- eh_frame_ptr_enc: 0x1b DW_EH_PE_pcrel | DW_EH_PE_sdata4
- fde_count_enc: 0x03 DW_EH_PE_udata4
- table_enc: 0x3b DW_EH_PE_datarel | DW_EH_PE_sdata4
- eh_frame_ptr: 0x3800 0000
- fde_count: 0x0600 0000
- binary search table:
- 0x0cf0ffff, 0x84000000
- 0x2cf0ffff, 0xac000000
- 0x3cf0ffff, 0x54000000
- 0x21f1ffff, 0xc4000000
- 0x4cf1ffff, 0xe4000000
- 0xacf1ffff, 0x2c010000
.eh_frame
The .eh_frame section has the same structure with .debug_frame, which follows DWARF format. It represents the table that describes how to set registers to restore the previous call frame at runtime. DWARF designers allow for having flexible mechanism to be able to unwind the stack with various expressions including constant values, arithmetic, memory dereference, register contents, and control flow.
It contains at least one or more Call Frame Information (CFI) records. Each CFI consists of two entry forms: Common Information Entry (CIE) and Frame Description Entry (FDE). Every CFI has a single CIE and one or more FDEs. CFI usually corresponds to a single object file. Likewise, so does FDE to a single function. However, there might be multiple CIEs and FDEs corresponding to the parts of a function when the function has a non-contiguous range in a virtual memory space. The following shows the fields of each entry in detail.
00000000: 1400 0000 0000 0000 017a 5200 0178 1001 .........zR..x..
00000010: 1b0c 0708 9001 0710 1400 0000 1c00 0000 ................
00000020: e0ef ffff 2b00 0000 0000 0000 0000 0000 ....+...........
00000030: 1400 0000 0000 0000 017a 5200 0178 1001 .........zR..x..
00000040: 1b0c 0708 9001 0000 2400 0000 1c00 0000 ........$.......
00000050: 80ef ffff 2000 0000 000e 1046 0e18 4a0f .... ......F..J.
00000060: 0b77 0880 003f 1a3b 2a33 2422 0000 0000 .w...?.;*3$"....
00000070: 1400 0000 4400 0000 78ef ffff 0800 0000 ....D...x.......
00000080: 0000 0000 0000 0000 1c00 0000 5c00 0000 ............\...
00000090: 55f0 ffff 2700 0000 0041 0e10 8602 430d U...'....A....C.
000000a0: 0662 0c07 0800 0000 4400 0000 7c00 0000 .b......D...|...
000000b0: 60f0 ffff 5d00 0000 0042 0e10 8f02 490e `...]....B....I.
000000c0: 188e 0345 0e20 8d04 450e 288c 0544 0e30 ...E. ..E.(..D.0
000000d0: 8606 480e 3883 0747 0e40 6a0e 3841 0e30 ..H.8..G.@j.8A.0
000000e0: 410e 2842 0e20 420e 1842 0e10 420e 0800 A.(B. B..B..B...
000000f0: 1000 0000 c400 0000 78f0 ffff 0100 0000 ........x.......
00000100: 0000 0000 0000 0000 ........
.comment
This section holds version control information. Showing the version of each compiler used to create the binary.
00000000: 4743 433a 2028 4465 6269 616e 2031 302e GCC: (Debian 10.
00000010: 322e 312d 3629 2031 302e 322e 3120 3230 2.1-6) 10.2.1 20
00000020: 3231 3031 3130 00 210110.
Segments
In order to execute the binary ELF files have segments which define how to load itself in memory, specifying permisions and data to be included.
Elf file type is DYN (Shared object file)
Entry point 0x1050
There are 11 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x0000000000000268 0x0000000000000268 R 0x8
INTERP 0x00000000000002a8 0x00000000000002a8 0x00000000000002a8
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000568 0x0000000000000568 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x00000000000001cd 0x00000000000001cd R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x0000000000000158 0x0000000000000158 R 0x1000
LOAD 0x0000000000002de8 0x0000000000003de8 0x0000000000003de8
0x0000000000000248 0x0000000000000250 RW 0x1000
DYNAMIC 0x0000000000002df8 0x0000000000003df8 0x0000000000003df8
0x00000000000001e0 0x00000000000001e0 RW 0x8
NOTE 0x00000000000002c4 0x00000000000002c4 0x00000000000002c4
0x0000000000000044 0x0000000000000044 R 0x4
GNU_EH_FRAME 0x0000000000002014 0x0000000000002014 0x0000000000002014
0x000000000000003c 0x000000000000003c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000002de8 0x0000000000003de8 0x0000000000003de8
0x0000000000000218 0x0000000000000218 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .plt.got .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .got.plt .data .bss
06 .dynamic
07 .note.gnu.build-id .note.ABI-tag
08 .eh_frame_hdr
09
10 .init_array .fini_array .dynamic .got
References
- Analysis of ELF format. GNU. Hash area and glibc symbol search from examples
- GNU Hash ELF Sections
- ELF: better symbol lookup via DT_GNU_HASH
- Inside ELF Symbol Tables
- What functions does GCC add to the linux ELF
- Symbol Versioning
- Version Requirements
- Version Symbol Section
- All about symbol versioning
- .init, .ctors, and .init_array
- executing init and fini
- Introduction to The ELF Format (Part VI): The Symbol Table and Relocations (Part 2) (k3170makan.com)
- Relative relocations and RELR
- System V - ABI
- The .init and .fini Sections
- Introduction to the ELF Format (Part V) : Understanding C start up .init_array and .fini_array sections
- Why GCC compiled C program needs .eh_frame section?
- text, data, bss, and dec
- The ELF file format
- An in-depth Explanation - linker.ld
- Sections (.bss) , (.rodata) and (.data) … where and how to place them?
- Sections Types
- Computer Science from the Bottom Up
- GNU Hash ELF Sections
- ELF Symbol Versioning
- ELF: better symbol lookup via DT_GNU_HASH
- glibc and DT_GNU_HASH
- All about Global Offset Table
- Processing ELF relocations - understanding the relocs, symbols, section data, and how they work together