I am writing an ELF parser as a side project and I have encountered a problem while trying to parse .note*
sections.
The documentation for ELF32 and ELF64 (available here and here, pages 42 and 13 respectively) says
These sections contain any number of note entries, each of which is an array of N-byte words in the byte order defined in the ELF file header.
where N is 4 for ELF32 and 8 for ELF64.
But if I take a look into an example hello world program, written in C and compiled with gcc (11.4.0), with readelf -x .note.gnu.property hello.x
I get
Hex dump of section '.note.gnu.property':
0x00000338 04000000 20000000 05000000 474e5500 .... .......GNU.
0x00000348 020000c0 04000000 03000000 00000000 ................
0x00000358 028000c0 04000000 01000000 00000000 ................
This section does not seem made by 8-byte words even though the ELF is 64 bits:
Output of readelf -h hello.x
:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1060
Start of program headers: 64 (bytes into file)
Start of section headers: 13976 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30
Moreover, the entries in the section does not seem to be aligned on an 8-byte boundary as the section header says. Output of readelf --sections hello.x
:
There are 31 section headers, starting at offset 0x3698:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
...
[ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338
0000000000000030 0000000000000000 A 0 0 8
...
I tried parsing the .note.gnu.property
section as an array of 8-byte words aligned on 8-byte boundaries but that resulted in reading out of the file since, instead of reading namesz=0x4
and descsz=0x20
, my program read namesz=0x2000000004
and tried reading that number of bytes from the file.
To conclude, it seems clear that the correct way to parse .note*
sections is to read 4-byte words aligned on 4-byte boundaries as if they were in an ELF32 file regardless of the actual EI_CLASS. I just don't understand why, maybe I am just misinterpreting some information in the documentation.
I just don't understand why, maybe I am just misinterpreting some information in the documentation.
You are mis-interpreting the documentation:
.note
section is 4 or 8-byte aligned.Elf{32,64}_Nhdr
, followed by note data. In /usr/include/elf.h
, you can see that Elf64_Nhdr
is: Elf64_Word n_namesz; Elf64_Word n_descsz; Elf64_Word n_type;
, and Elf64_Word
is a uint32_t
, i.e. a 4-byte quantity.