This page looks best with JavaScript enabled

Dissecting a Hello World

 ·  ☕ 44 min read

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:

1
2
3
4
5
#include <stdio.h>
int main(int argc, char **argv) {
   printf("Hello World!");
   return 0;
}

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.

1
2
3
4
5
typedef struct elf64_note {
  Elf64_Word n_namesz;	/* Name size */
  Elf64_Word n_descsz;	/* Content size */
  Elf64_Word n_type;	/* Content type */
} Elf64_Nhdr;

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.
  • 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.

1
2
3
4
5
6
7
typedef struct {
	Elf64_Half    vn_version;
	Elf64_Half    vn_cnt;
	Elf64_Word    vn_file;
	Elf64_Word    vn_aux;
	Elf64_Word    vn_next;
} Elf64_Verneed;
  • 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.

1
2
3
4
5
6
7
typedef struct {
	Elf64_Word    vna_hash;
	Elf64_Half    vna_flags;
	Elf64_Half    vna_other;
	Elf64_Word    vna_name;
	Elf64_Word    vna_next;
} Elf64_Vernaux;
  • 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) {
		char *elf_interpreter;

		if (elf_ppnt->p_type == PT_GNU_PROPERTY) {
			elf_property_phdata = elf_ppnt;
			continue;
		}

		if (elf_ppnt->p_type != PT_INTERP)
			continue;

		/*
		 * This is the program interpreter used for shared libraries -
		 * for now assume that this is an a.out format binary.
		 */
		retval = -ENOEXEC;
		if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2)
			goto out_free_ph;

		retval = -ENOMEM;
		elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL);
		if (!elf_interpreter)
			goto out_free_ph;

		retval = elf_read(bprm->file, elf_interpreter, elf_ppnt->p_filesz,
				  elf_ppnt->p_offset);
...

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.

1
2
3
4
5
6
7
8
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;

.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.

1
2
3
4
5
6
typedef struct
{
  Elf64_Addr	r_offset;		/* Address */
  Elf64_Xword	r_info;			/* Relocation type and symbol index */
  Elf64_Sxword	r_addend;		/* Addend */
} Elf64_Rela;

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:

1
*(Elf_Addr*)(base+r_offset) += base + addend;

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

Share on

ITasahobby
WRITTEN BY
ITasahobby
InTernet lover