The ELF: What the ARM Assembler Generates on Raspberry Pi

1 week ago 5

In my previous post, I wrote a simple “Hello World!” in ARM assembly on the Raspberry Pi. This post will explore what happens when the assembler runs. We will have a look at the resulting binary object file that it creates, decode its raw bytes and dissect the ELF format by hand.

Hereafter we are just copying the hexdump of the object file that was created in the previous post.

00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 01 00 28 00 01 00 00 00 00 00 00 00 00 00 00 00 |..(.............| 00000020 74 01 00 00 00 00 00 05 34 00 00 00 00 00 28 00 |t.......4.....(.| 00000030 09 00 08 00 01 00 a0 e3 20 10 9f e5 0c 20 a0 e3 |........ .... ..| 00000040 04 70 a0 e3 00 00 00 ef 01 70 a0 e3 00 00 00 ef |.p.......p......| 00000050 48 65 6c 6c 6f 2c 20 41 52 4d 21 0a 00 00 00 00 |Hello, ARM!.....| 00000060 1c 00 00 00 41 11 00 00 00 61 65 61 62 69 00 01 |....A....aeabi..| 00000070 07 00 00 00 08 01 00 00 00 00 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000090 00 00 00 00 03 00 01 00 00 00 00 00 00 00 00 00 |................| 000000a0 00 00 00 00 03 00 03 00 00 00 00 00 00 00 00 00 |................| 000000b0 00 00 00 00 03 00 04 00 01 00 00 00 00 00 00 00 |................| 000000c0 00 00 00 00 00 00 01 00 04 00 00 00 1c 00 00 00 |................| 000000d0 00 00 00 00 00 00 01 00 08 00 00 00 1c 00 00 00 |................| 000000e0 00 00 00 00 00 00 01 00 08 00 00 00 2c 00 00 00 |............,...| 000000f0 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 |................| 00000100 00 00 00 00 03 00 05 00 0b 00 00 00 00 00 00 00 |................| 00000110 00 00 00 00 10 00 01 00 00 24 61 00 6d 73 67 00 |.........$a.msg.| 00000120 24 64 00 5f 73 74 61 72 74 00 00 00 2c 00 00 00 |$d._start...,...| 00000130 02 01 00 00 00 2e 73 79 6d 74 61 62 00 2e 73 74 |......symtab..st| 00000140 72 74 61 62 00 2e 73 68 73 74 72 74 61 62 00 2e |rtab..shstrtab..| 00000150 72 65 6c 2e 74 65 78 74 00 2e 64 61 74 61 00 2e |rel.text..data..| 00000160 62 73 73 00 2e 41 52 4d 2e 61 74 74 72 69 62 75 |bss..ARM.attribu| 00000170 74 65 73 00 00 00 00 00 00 00 00 00 00 00 00 00 |tes.............| 00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000190 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 00 00 |................| 000001a0 01 00 00 00 06 00 00 00 00 00 00 00 34 00 00 00 |............4...| 000001b0 30 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |0...............| 000001c0 00 00 00 00 1b 00 00 00 09 00 00 00 40 00 00 00 |............@...| 000001d0 00 00 00 00 2c 01 00 00 08 00 00 00 06 00 00 00 |....,...........| 000001e0 01 00 00 00 04 00 00 00 08 00 00 00 25 00 00 00 |............%...| 000001f0 01 00 00 00 03 00 00 00 00 00 00 00 64 00 00 00 |............d...| 00000200 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000210 00 00 00 00 2b 00 00 00 08 00 00 00 03 00 00 00 |....+...........| 00000220 00 00 00 00 64 00 00 00 00 00 00 00 00 00 00 00 |....d...........| 00000230 00 00 00 00 01 00 00 00 00 00 00 00 30 00 00 00 |............0...| 00000240 03 00 00 70 00 00 00 00 00 00 00 00 64 00 00 00 |...p........d...| 00000250 12 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000260 00 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 |................| 00000270 00 00 00 00 78 00 00 00 a0 00 00 00 07 00 00 00 |....x...........| 00000280 09 00 00 00 04 00 00 00 10 00 00 00 09 00 00 00 |................| 00000290 03 00 00 00 00 00 00 00 00 00 00 00 18 01 00 00 |................| 000002a0 12 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 000002b0 00 00 00 00 11 00 00 00 03 00 00 00 00 00 00 00 |................| 000002c0 00 00 00 00 34 01 00 00 40 00 00 00 00 00 00 00 |....4...@.......| 000002d0 00 00 00 00 01 00 00 00 00 00 00 00 |............| 000002dc 000002dc

After some googling, I found out that the object file is actually described through the ELF (Executable and Linking Format) specification, which in turn is part of the more broad Application Binary Interface (ABI) specification. The latter defines operating system and application interfaces that are necessary to construct an execution environment for applications. The most recent (well, referencing today 29/05/2025) ABI standard can be found here. More specifically, this is the System V ABI which is composed from 2 parts, the generic specification (the gABI) and the architecture specific extensions. Chapters 4 and 5 of the gABI have recently been updated and the updates can be found here. It is chapter 4 “Object files” that is of interest to get the parsing going!

The object file is composed of different structures, we’ll typically find the ELF header, section header table and sections. The ELF header provides some metadata on how to interprete the object file, the section header table is an array of section header entries that describe the sections and the sections themselves are the bits and bytes that contain the actual data. But we’ll need to start parsing the ELF header to get a better idea about the structure of the object file.

As can be found in Chapter 4, the ELF header has the following structure:

typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr;

Each of the members will be discussed hereafter, but you can always reference the specification.

e_type

We see that the lengths in the header below are referenced as Elf32_Half, Elf32_Word, Elf32_Addr, Elf32_Off, it is interesting to know that these represent 2, 4, 4 and 4 bytes respectively. It makes sense to understand that Addr means that the value will signify an address and Off an offset.

NameLengthValueInterpretation
e_ident16 bytes0x7f 0x45 0x4c 0x46 0x01 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00see below
e_typeElf32_Half0x00 0x01ET_REL = relocatable file
e_machineElf32_Half0x00 0x28EM_ARM = Advanced RISC Machines ARM
e_versionElf32_Word0x00 0x00 0x00 0x01EV_CURRENT = Current Version
e_entryElf32_Addr0x00 0x00 0x00 0x00Since this member holds zero, the file has no associated entry point
e_phoffElf32_Off0x00 0x00 0x00 0x00Since this member holds zero, the file has no program header table
e_shoffElf32_Off0x00 0x00 0x01 0x74Since this member is non-zero, it holds the section header table’s file offset in bytes
e_flagsElf32_Word0x05 0x00 0x00 0x00Flag names take the form of EF_machine_flag
e_ehsizeElf32_Half0x00 0x34This one indicates that the ELF header’s size is 52 bytes long
e_phentsizeElf32_Half0x00 0x00One entry in the file’s program header table measures 0 bytes
e_phnumElf32_Half0x00 0x00There are 0 entries in the program header table. Since e_phnum is 0, there is no program header table.
e_shentsizeElf32_Half0x00 0x28A section header’s size is 40 bytes. A section header is one entry in the section header table and all entries are the same size.
e_shnumElf32_Half0x00 0x09You will find 9 entries in the section header table. So the section header table entry is 360 bytes (e_shnum times e_shentsize). In case there is no section header table, this value should have been 0.
e_shstrndxElf32_Half0x00 0x08This holds the section header table index of the entry associated with the section name string table.

e_ident

Parsing this file, by hand for this first exercise, according to the updated chapter 4 of the general ABI specification, we notice the first 4 bytes indicating 0x7F, 0x45, 0x4C, 0x46. These are a so called “magic” number as they are just defined as such. The first byte will always be 0x7F, where the following 3 bytes represent the ASCII code for ELF. The fifth byte EU_CLASS is set to 0x01 representing the ELFCLASS32, which means we are dealing with 32-bit objects and supports machines with 32-bit architectures. The next byte encodes the EI_DATA, since the data is set to 0x01, it represents ELFDATA2LSB, meaning that the byte address 0 is on the left. So imagine we would have to store the hexstring 0x01020304, this would mean that the bytes will be stored as followed:

hexstring0x040x030x020x01
address3210
stored hexstring0x010x020x030x04

Next to EI_DATA, we have EI_VERSION encoded in the 7th byte, which is currently EV_CURRENT, encoded as 0x01. Following EI_VERSION, the EI_OSABI identifies the OS- of ABI-specific ELF extension used by this file. The 0x00 just declares that there are no extensions to be taken into account (or unspecified). EI_ABIVERSION also declares that this is unspecified. The rest of the bytes are then just padding bytes for this header.

Exploring the ELF Sections

The next important concept in the object file are sections since they hold most of the object file’s information. Every section is described through information in the section header table. The latter being an array of ELf32_Shdr structures (or ELf64_Shdr structures depending on the architecture). The ELF Header’s e_shoff, e-shnum and e_shentsize provides you some information how to find and interprete the object file’s section header table as they represent the byte offset of the section header table from the beginning of the file, the number of entries and the size of an entry respectively.

So referring to our parsed ELF header above, we already found that:

NameValueInterpretation
e_shoff0x00 0x00 0x01 0x74The section header table’s byte offset is 372 from the beginning of the file
e_shnum0x00 0x09We will find 9 section header table entries
e_shentsize0x00 0x28An entry of the section header table has 40 bytes

So the section header table starts at byte 372 (0x174) and ends at byte 731 (= 372 + (9 * 40 -1)) (0x2DB). Which means that from our hexdump above, the section header table is the following (and I’ve replaced the byte values by XX for the bytes that are not part of the section header table):

00000170 XX XX XX XX 00 00 00 00 00 00 00 00 00 00 00 00 |tes.............| 00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000190 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 00 00 |................| 000001a0 01 00 00 00 06 00 00 00 00 00 00 00 34 00 00 00 |............4...| 000001b0 30 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |0...............| 000001c0 00 00 00 00 1b 00 00 00 09 00 00 00 40 00 00 00 |............@...| 000001d0 00 00 00 00 2c 01 00 00 08 00 00 00 06 00 00 00 |....,...........| 000001e0 01 00 00 00 04 00 00 00 08 00 00 00 25 00 00 00 |............%...| 000001f0 01 00 00 00 03 00 00 00 00 00 00 00 64 00 00 00 |............d...| 00000200 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000210 00 00 00 00 2b 00 00 00 08 00 00 00 03 00 00 00 |....+...........| 00000220 00 00 00 00 64 00 00 00 00 00 00 00 00 00 00 00 |....d...........| 00000230 00 00 00 00 01 00 00 00 00 00 00 00 30 00 00 00 |............0...| 00000240 03 00 00 70 00 00 00 00 00 00 00 00 64 00 00 00 |...p........d...| 00000250 12 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000260 00 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 |................| 00000270 00 00 00 00 78 00 00 00 a0 00 00 00 07 00 00 00 |....x...........| 00000280 09 00 00 00 04 00 00 00 10 00 00 00 09 00 00 00 |................| 00000290 03 00 00 00 00 00 00 00 00 00 00 00 18 01 00 00 |................| 000002a0 12 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 000002b0 00 00 00 00 11 00 00 00 03 00 00 00 00 00 00 00 |................| 000002c0 00 00 00 00 34 01 00 00 40 00 00 00 00 00 00 00 |....4...@.......| 000002d0 00 00 00 00 01 00 00 00 00 00 00 00 |............| 000002dc

Each section header entry follows this structure:

typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr;

So, we have the following section header table entries:

00000170 XX XX XX XX 00 00 00 00 00 00 00 00 00 00 00 00 |tes.............| 00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000190 00 00 00 00 00 00 00 00 00 00 00 00 XX XX XX XX |................|

Well, according to the spec, it seems that index 0, called SHN_UNDEF, is actually one of the special section indexes. It marks an undefined, missing, irrelevant or otherwise meaningless section reference. Given its filled with zeroes, I would currently go for an irrelevant section…

00000190 XX XX XX XX XX XX XX XX XX XX XX XX 1f 00 00 00 |................| 000001a0 01 00 00 00 06 00 00 00 00 00 00 00 34 00 00 00 |............4...| 000001b0 30 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |0...............| 000001c0 00 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX |............@...|

This is the first entry with some actual values. So trying to parse this according to the spec seems to result in the folowing:

NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x1fThe name is defined by the string at index 31 of the string table: .text
sh_typeElf32_Word0x00 0x00 0x00 0x01The type of this section is SHT_PROGBITS. A section holding information defined by the program. Format and meaning are determined solely by the program.
sh_flagsElf32_Word0x00 0x00 0x00 0x06This means that flags SHF_ALLOC (0x02) and SHF_EXECINSTR (0x04) are set. SHF_ALLOC indicates that section will occupy memory during process execution. The other flag indicates that the section contains executable machine instructions.
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x00 0x34This is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0x30Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_PROGBITS
sh_infoElf32_Word0x00 0x00 0x00 0x00Contains extra information whose interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_PROGBITS
sh_addralignElf32_Word0x00 0x00 0x00 0x04Some sections have address alignment constraints. In this case, I’m not yet 100% certain what this value of 4 actually represents
sh_entsizeElf32_Word0x00 0x00 0x00 0x00The value of 0 indicates that the section does not hold a table of fixed-size entries

Section [0x34 - 0x63]

Given the above section header table entry, the section is actually consisting out of the following bytes:

00000030 XX XX XX XX 01 00 a0 e3 20 10 9f e5 0c 20 a0 e3 |........ .... ..| 00000040 04 70 a0 e3 00 00 00 ef 01 70 a0 e3 00 00 00 ef |.p.......p......| 00000050 48 65 6c 6c 6f 2c 20 41 52 4d 21 0a 00 00 00 00 |Hello, ARM!.....| 00000060 1c 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX |....A....aeabi..|

Since .text indicates that the section holds the executable instructions of the program, I would expect that the section represents the binary instructions of the assembly code. But, I won’t deep dive into it at this point in time.

000001c0 XX XX XX XX 1b 00 00 00 09 00 00 00 40 00 00 00 |............@...| 000001d0 00 00 00 00 2c 01 00 00 08 00 00 00 06 00 00 00 |....,...........| 000001e0 01 00 00 00 04 00 00 00 08 00 00 00 XX XX XX XX |............%...|
NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x1bThe name is defined by the string at index 27 of the string table: .rel.text
sh_typeElf32_Word0x00 0x00 0x00 0x09SHT_REL This section holds relocation entries without explicit addends. But, I’m not quite sure what this means, yet…
sh_flagsElf32_Word0x00 0x00 0x00 0x40SHF_INFO_LINK indicates that the sh_info field of this section header holds a section header table index
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x01 0x2CThis is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0x08Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x06This should represent the section header index of the associated symbol table. As defined by figure 4-12 in the spec
sh_infoElf32_Word0x00 0x00 0x00 0x01The section header index of the section to which the relocation applies. As defined by figure 4-12 in the spec
sh_addralignElf32_Word0x00 0x00 0x00 0x04Some sections have address alignment constraints. In this case, I’m not yet 100% certain what this value of 4 actually represents
sh_entsizeElf32_Word0x00 0x00 0x00 0x08This section will hold a table of fixed-size entries, each entry will be 8 bytes

Section [0x12C - 0x133]

00000120 XX XX XX XX XX XX XX XX XX XX XX XX 2c 00 00 00 |$d._start...,...| 00000130 02 01 00 00 XX XX XX XX XX XX XX XX XX XX XX XX |......symtab..st|

.rel.text indicates that this section is holding relocation information as defined here. Not further looking into this for the time being.

000001e0 XX XX XX XX XX XX XX XX XX XX XX XX 25 00 00 00 |............%...| 000001f0 01 00 00 00 03 00 00 00 00 00 00 00 64 00 00 00 |............d...| 00000200 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000210 00 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX |....+...........|
NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x25The name is defined by the string at index 37 of the string table: .data
sh_typeElf32_Word0x00 0x00 0x00 0x01SHT_PROGBITS A section holding information defined by the program. Format and meaning are determined solely by the program
sh_flagsElf32_Word0x00 0x00 0x00 0x03This means that flags SHF_WRITE (0x01) and SHF_ALLOC (0x02) are set. Meaning that the section contains data that should be writable during process execution and that the section occupies memory during process execution
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x00 0x64This is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0x00Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_PROGBITS
sh_infoElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_PROGBITS
sh_addralignElf32_Word0x00 0x00 0x00 0x01A value of 1 indicates that there are no alignment constraints
sh_entsizeElf32_Word0x00 0x00 0x00 0x00The value of 0 indicates that the section does not hold a table of fixed-size entries

We do have to seem a section offset, however the size of the section appears to be 0. The .data section should also contain initialized data that contributes to the program’s memory image. Still puzzled somewhat why this section can have a size of 0 bytes in this case…

00000210 XX XX XX XX 2b 00 00 00 08 00 00 00 03 00 00 00 |....+...........| 00000220 00 00 00 00 64 00 00 00 00 00 00 00 00 00 00 00 |....d...........| 00000230 00 00 00 00 01 00 00 00 00 00 00 00 XX XX XX XX |............0...|
NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x2bThe name is defined by the string at index 43 of the string table: .bss
sh_typeElf32_Word0x00 0x00 0x00 0x08SHT_NOBITS A section that occupies no space in the file.
sh_flagsElf32_Word0x00 0x00 0x00 0x03This means that flags SHF_WRITE (0x01) and SHF_ALLOC (0x02) are set. Meaning that the section contains data that should be writable during process execution and that the section occupies memory during process execution
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x00 0x64Since this is a section of type SHT_NOBITS, this field contains the conceptual file offset
sh_sizeElf32_Word0x00 0x00 0x00 0x00Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_NOBITS
sh_infoElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_NOBITS
sh_addralignElf32_Word0x00 0x00 0x00 0x01A value of 1 indicates that there are no alignment constraints
sh_entsizeElf32_Word0x00 0x00 0x00 0x00The value of 0 indicates that the section does not hold a table of fixed-size entries

.bss sections hold uninitialized data that contribute to the program’s memory image. Data are initialized with zeroes when the program begins to run.

00000230 XX XX XX XX XX XX XX XX XX XX XX XX 30 00 00 00 |............0...| 00000240 03 00 00 70 00 00 00 00 00 00 00 00 64 00 00 00 |...p........d...| 00000250 12 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000260 00 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX |................|
NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x30The name is defined by the string at index 48 of the string table: .ARM.attributes
sh_typeElf32_Word0x70 0x00 0x00 0x03This value is in between SHT_LOPROC (0x70000000) and SHT_HIPROC (0x7FFFFFFF), which are values reserved for processor-specific semantics
sh_flagsElf32_Word0x00 0x00 0x00 0x00No flags
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x00 0x64This is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0x12Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant for this header type
sh_infoElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant for this header type
sh_addralignElf32_Word0x00 0x00 0x00 0x01A value of 1 indicates that there are no alignment constraints
sh_entsizeElf32_Word0x00 0x00 0x00 0x00The value of 0 indicates that the section does not hold a table of fixed-size entries

Section [0x64 - 0x75]

00000060 XX XX XX XX 41 11 00 00 00 61 65 61 62 69 00 01 |....A....aeabi..| 00000070 07 00 00 00 08 01 XX XX XX XX XX XX XX XX XX XX |................|

Not sure what to make from this section, yet…

00000260 XX XX XX XX 01 00 00 00 02 00 00 00 00 00 00 00 |................| 00000270 00 00 00 00 78 00 00 00 a0 00 00 00 07 00 00 00 |....x...........| 00000280 09 00 00 00 04 00 00 00 10 00 00 00 XX XX XX XX |................|
NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x01The name is defined by the string at index 1 of the string table: .symtab
sh_typeElf32_Word0x00 0x00 0x00 0x02SHT_SYMTAB Section that holds a symbol table
sh_flagsElf32_Word0x00 0x00 0x00 0x00No flags
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x00 0x78This is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0xa0Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x07The section header index of the associated string table
sh_infoElf32_Word0x00 0x00 0x00 0x09One greater than the symbol table index of the last local symbol (binding STB_LOCAL)
sh_addralignElf32_Word0x00 0x00 0x00 0x04Some sections have address alignment constraints. In this case, I’m not yet 100% certain what this value of 4 actually represents
sh_entsizeElf32_Word0x00 0x00 0x00 0x10This section will hold a table of fixed-size entries, each entry will be 16 bytes

Section [0x78 - 0x117]

00000070 XX XX XX XX XX XX XX XX 00 00 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000090 00 00 00 00 03 00 01 00 00 00 00 00 00 00 00 00 |................| 000000a0 00 00 00 00 03 00 03 00 00 00 00 00 00 00 00 00 |................| 000000b0 00 00 00 00 03 00 04 00 01 00 00 00 00 00 00 00 |................| 000000c0 00 00 00 00 00 00 01 00 04 00 00 00 1c 00 00 00 |................| 000000d0 00 00 00 00 00 00 01 00 08 00 00 00 1c 00 00 00 |................| 000000e0 00 00 00 00 00 00 01 00 08 00 00 00 2c 00 00 00 |............,...| 000000f0 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 |................| 00000100 00 00 00 00 03 00 05 00 0b 00 00 00 00 00 00 00 |................| 00000110 00 00 00 00 10 00 01 00 XX XX XX XX XX XX XX XX |.........$a.msg.|

This section holds a symbol table and its definition can be found here.

00000280 XX XX XX XX XX XX XX XX XX XX XX XX 09 00 00 00 |................| 00000290 03 00 00 00 00 00 00 00 00 00 00 00 18 01 00 00 |................| 000002a0 12 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 000002b0 00 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX |................|
NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x09The name is defined by the string at index 9 of the string table: .strtab
sh_typeElf32_Word0x00 0x00 0x00 0x03SHT_STRTAB This section holds a stringtable
sh_flagsElf32_Word0x00 0x00 0x00 0x00No flags
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x01 0x18This is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0x12Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant for this header type
sh_infoElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant for this header type
sh_addralignElf32_Word0x00 0x00 0x00 0x01A value of 1 indicates that there are no alignment constraints
sh_entsizeElf32_Word0x00 0x00 0x00 0x00The value of 0 indicates that the section does not hold a table of fixed-size entries

Section [0x118 - 0x129] - string table

The .strtab section holds strings, typically, the names that are associated with the symbol table entries.

00000110 XX XX XX XX XX XX XX XX 00 24 61 00 6d 73 67 00 |.........$a.msg.| 00000120 24 64 00 5f 73 74 61 72 74 00 XX XX XX XX XX XX |$d._start...,...|

So in order to parse this, we slightly transform the above table into the following

Index+0+1+2+3+4+5+6+7+8+9
0002461006D7367002464
10005f737461727400

Now, applying converting the hex values to their ASCII representation, we get:

Index+0+1+2+3+4+5+6+7+8+9
0\0$a\0msg\0$d
10\0_start\0

Resulting in the following string table

IndexString
0none
1$a
4msg
8$d
27.rel.text
11_start

We specifically notice how this section header table entry is indexed by e_shstrndx. By definition, this entry is associated with the section named “string table”.

000002b0 XX XX XX XX 11 00 00 00 03 00 00 00 00 00 00 00 |................| 000002c0 00 00 00 00 34 01 00 00 40 00 00 00 00 00 00 00 |....4...@.......| 000002d0 00 00 00 00 01 00 00 00 00 00 00 00 |............|

Lets have a look at what can be found inside this entry:

NameLengthValueInterpretation
sh_nameElf32_Word0x00 0x00 0x00 0x11The name is defined by the string at index 17 of the string table: .shstrtab
sh_typeElf32_Word0x00 0x00 0x00 0x03SHT_STRTAB So the section will be holding a string table
sh_flagsElf32_Word0x00 0x00 0x00 0x00No flags
sh_addrElf32_Addr0x00 0x00 0x00 0x00A 0 seems to indicate that the section will not appear in the memory image of a process
sh_offsetElf32_Off0x00 0x00 0x01 0x34This is the byte offset from the beginning of the file to the first byte in the section
sh_sizeElf32_Word0x00 0x00 0x00 0x40Section size in bytes
sh_linkElf32_Word0x00 0x00 0x00 0x00Contains a section header table index link, interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_STRTAB
sh_infoElf32_Word0x00 0x00 0x00 0x00Contains extra information whose interpretation depends on the section type. It does not seem relevant though for an sh_type of SHT_STRTAB
sh_addralignElf32_Word0x00 0x00 0x00 0x01A value of 1 indicates that there are no alignment constraints
sh_entsizeElf32_Word0x00 0x00 0x00 0x00The value of 0 indicates that the section does not hold a table of fixed-size entries
00000130 XX XX XX XX 00 2e 73 79 6d 74 61 62 00 2e 73 74 |......symtab..st| 00000140 72 74 61 62 00 2e 73 68 73 74 72 74 61 62 00 2e |rtab..shstrtab..| 00000150 72 65 6c 2e 74 65 78 74 00 2e 64 61 74 61 00 2e |rel.text..data..| 00000160 62 73 73 00 2e 41 52 4d 2e 61 74 74 72 69 62 75 |bss..ARM.attribu| 00000170 74 65 73 00 XX XX XX XX XX XX XX XX XX XX XX XX |tes.............|

However, in order to have a better undertanding of how the indexing into this table will work, I’ll slightly rewrite this as follows. It can be noticed how the indexes is determined by

Index+0+1+2+3+4+5+6+7+8+9
0002E73796D746162002E
10737472746162002E7368
20737472746162002E7265
306C2E74657874002E6461
407461002E627373002E41
50524D2E61747472696275
6074657300

And when converting the hex values into there ASCII representation, we have:

Index+0+1+2+3+4+5+6+7+8+9
0\0.symtab\0.
10strtab\0.sh
20strtab\0.re
30l.text\0.da
40ta\0.bss\0.A
50RM.attribu
60tes\0

And in order to have an easy and quick look-up table:

IndexString
0none
1.symtab
9.strtab
17.shstrtab
27.rel.text
31.text
37.data
43.bss
48.ARM.attributes

Please note how you can just index whereever you want in the string table to define a string. Here, at index 31, the string .text is actually a substring of .rel.text.

Verifying with Readelf!

Luckly there is no need to parse everything by hand, the readelf command parses the ELF file for you and provides some readable output.

Returns the following

ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: ARM Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 372 (bytes into file) Flags: 0x5000000, Version5 EABI Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 9 Section header string table index: 8 Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 000030 00 AX 0 0 4 [ 2] .rel.text REL 00000000 00012c 000008 08 I 6 1 4 [ 3] .data PROGBITS 00000000 000064 000000 00 WA 0 0 1 [ 4] .bss NOBITS 00000000 000064 000000 00 WA 0 0 1 [ 5] .ARM.attributes ARM_ATTRIBUTES 00000000 000064 000012 00 0 0 1 [ 6] .symtab SYMTAB 00000000 000078 0000a0 10 7 9 4 [ 7] .strtab STRTAB 00000000 000118 000012 00 0 0 1 [ 8] .shstrtab STRTAB 00000000 000134 000040 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), y (purecode), p (processor specific) There are no section groups in this file. There are no program headers in this file. There is no dynamic section in this file. Relocation section '.rel.text' at offset 0x12c contains 1 entry: Offset Info Type Sym.Value Sym. Name 0000002c 00000102 R_ARM_ABS32 00000000 .text There are no unwind sections in this file. Symbol table '.symtab' contains 10 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 SECTION LOCAL DEFAULT 1 2: 00000000 0 SECTION LOCAL DEFAULT 3 3: 00000000 0 SECTION LOCAL DEFAULT 4 4: 00000000 0 NOTYPE LOCAL DEFAULT 1 $a 5: 0000001c 0 NOTYPE LOCAL DEFAULT 1 msg 6: 0000001c 0 NOTYPE LOCAL DEFAULT 1 $d 7: 0000002c 0 NOTYPE LOCAL DEFAULT 1 $d 8: 00000000 0 SECTION LOCAL DEFAULT 5 9: 00000000 0 NOTYPE GLOBAL DEFAULT 1 _start No version information found in this file. Attribute Section: aeabi File Attributes Tag_ARM_ISA_use: Yes

Which provides a nice summary of everything that was decoded by hand above!

Inspecting this object file has taken me deep into the ELF format. Even this only scratches the surface, it already helped me to have a better understanding of what the assembler is doing. I would certainly still like to have a better understanding of how the assembler instructions are converted in a bitwise representation and the resulting .text section. I’m curious how the GNU linker and GNU debugger will modify these binary files!

This was Steven documenting his embedded journeys! If you’ve got questions, want to share your own assembly experiences, or spot something I got wrong — drop a comment or reach out. I’d love to hear from you!

Coming up: The GNU linker, and the debugger! Or might as well get a bit more hands-on with a distance sensor :)

comments powered by

Read Entire Article