Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I want to create a c program that creates .o files for the linker on my computer (ld). Gcc does this when I do the command gcc -c myfile.c. Are there any resources that show how to make an object file for a linker?
In order to create a file similar to a file produced by gcc -c, it is important to first understand the format of the file produced.
First, create a file with gcc, and then see if it's format can be reverse-engineered. I will use the following C program (hello.c) to perform this task:
#include <stdio.h>
int main(void)
{
printf("Hello world\n");
return(0);
}
Now, compile the file without linking it:
gcc -Wall -c -o hello.o hello.c
The above code will create hello.o from hello.c. This file is compiled, but not yet linked.
Many files today contain bytes in the header of the file that help identify its format. These identifying bytes are termed 'file magic'. Google 'file magic' and you can find details on how to identify may types of files.
To identify this file type, look for a magic number in the first few lines of a hexdump of the file:
> hexdump -Cn 64 hello.o
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 50 04 40 00 00 00 00 00 |..>.....P.#.....|
00000020 40 00 00 00 00 00 00 00 18 1a 00 00 00 00 00 00 |#...............|
00000030 00 00 00 00 40 00 38 00 09 00 40 00 2a 00 27 00 |....#.8...#.*.'.|
00000040
The identity of the file's format is revealed, in this case, by the first few bytes of the file; 45 4c 46 = ELF. Hence, the output of gcc -c is a file in the ElF format.
Hence, in order to create similar output from a C program, an understanding of the ELF file format is required.
Many *nix systems include a program called readelf that will translate the contents of an ELF file. For example:
> readelf -a hello.o
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: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400450
Start of program headers: 64 (bytes into file)
Start of section headers: 6680 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 42
Section header string table index: 39
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.SuSE NOTE 0000000000400274 00000274
0000000000000018 0000000000000000 A 0 0 4
[ 4] .note.gnu.build-i NOTE 000000000040028c 0000028c
0000000000000024 0000000000000000 A 0 0 4
[ 5] .hash HASH 00000000004002b0 000002b0
0000000000000024 0000000000000004 A 7 0 8
[ 6] .gnu.hash GNU_HASH 00000000004002d8 000002d8
000000000000001c 0000000000000000 A 7 0 8
[ 7] .dynsym DYNSYM 00000000004002f8 000002f8
0000000000000060 0000000000000018 A 8 1 8
[ 8] .dynstr STRTAB 0000000000400358 00000358
000000000000003d 0000000000000000 A 0 0 1
[ 9] .gnu.version VERSYM 0000000000400396 00000396
0000000000000008 0000000000000002 A 7 0 2
[10] .gnu.version_r VERNEED 00000000004003a0 000003a0
0000000000000020 0000000000000000 A 8 1 8
[11] .rela.dyn RELA 00000000004003c0 000003c0
0000000000000018 0000000000000018 A 7 0 8
[12] .rela.plt RELA 00000000004003d8 000003d8
0000000000000030 0000000000000018 A 7 14 8
[13] .init PROGBITS 0000000000400408 00000408
0000000000000018 0000000000000000 AX 0 0 4
[14] .plt PROGBITS 0000000000400420 00000420
0000000000000030 0000000000000010 AX 0 0 16
[15] .text PROGBITS 0000000000400450 00000450
00000000000001e8 0000000000000000 AX 0 0 16
[16] .fini PROGBITS 0000000000400638 00000638
0000000000000016 0000000000000000 AX 0 0 4
[17] .rodata PROGBITS 0000000000400650 00000650
0000000000000010 0000000000000000 A 0 0 4
[18] .eh_frame_hdr PROGBITS 0000000000400660 00000660
0000000000000034 0000000000000000 A 0 0 4
[19] .eh_frame PROGBITS 0000000000400698 00000698
00000000000000dc 0000000000000000 A 0 0 8
[20] .ctors PROGBITS 0000000000600e30 00000e30
0000000000000010 0000000000000000 WA 0 0 8
[21] .dtors PROGBITS 0000000000600e40 00000e40
0000000000000010 0000000000000000 WA 0 0 8
[22] .jcr PROGBITS 0000000000600e50 00000e50
0000000000000008 0000000000000000 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000600e58 00000e58
00000000000001a0 0000000000000010 WA 8 0 8
[24] .got PROGBITS 0000000000600ff8 00000ff8
0000000000000008 0000000000000008 WA 0 0 8
[25] .got.plt PROGBITS 0000000000601000 00001000
0000000000000028 0000000000000008 WA 0 0 8
[26] .data PROGBITS 0000000000601028 00001028
0000000000000010 0000000000000000 WA 0 0 8
[27] .bss NOBITS 0000000000601038 00001038
0000000000000010 0000000000000000 WA 0 0 8
[28] .comment PROGBITS 0000000000000000 00001038
0000000000000039 0000000000000001 MS 0 0 1
[29] .comment.SUSE.OPT PROGBITS 0000000000000000 00001071
0000000000000006 0000000000000001 MS 0 0 1
[30] .debug_aranges PROGBITS 0000000000000000 00001080
0000000000000060 0000000000000000 0 0 16
[31] .debug_pubnames PROGBITS 0000000000000000 000010e0
000000000000005f 0000000000000000 0 0 1
[32] .debug_info PROGBITS 0000000000000000 0000113f
0000000000000232 0000000000000000 0 0 1
[33] .debug_abbrev PROGBITS 0000000000000000 00001371
0000000000000133 0000000000000000 0 0 1
[34] .debug_line PROGBITS 0000000000000000 000014a4
000000000000011e 0000000000000000 0 0 1
[35] .debug_frame PROGBITS 0000000000000000 000015c8
0000000000000058 0000000000000000 0 0 8
[36] .debug_str PROGBITS 0000000000000000 00001620
0000000000000115 0000000000000001 MS 0 0 1
[37] .debug_loc PROGBITS 0000000000000000 00001735
00000000000000fe 0000000000000000 0 0 1
[38] .debug_ranges PROGBITS 0000000000000000 00001833
0000000000000050 0000000000000000 0 0 1
[39] .shstrtab STRTAB 0000000000000000 00001883
0000000000000192 0000000000000000 0 0 1
[40] .symtab SYMTAB 0000000000000000 00002498
00000000000007c8 0000000000000018 41 65 8
[41] .strtab STRTAB 0000000000000000 00002c60
0000000000000244 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000774 0x0000000000000774 R E 200000
LOAD 0x0000000000000e30 0x0000000000600e30 0x0000000000600e30
0x0000000000000208 0x0000000000000218 RW 200000
DYNAMIC 0x0000000000000e58 0x0000000000600e58 0x0000000000600e58
0x00000000000001a0 0x00000000000001a0 RW 8
NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x000000000000005c 0x000000000000005c R 4
GNU_EH_FRAME 0x0000000000000660 0x0000000000400660 0x0000000000400660
0x0000000000000034 0x0000000000000034 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
GNU_RELRO 0x0000000000000e30 0x0000000000600e30 0x0000000000600e30
0x00000000000001d0 0x00000000000001d0 R 1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.SuSE .note.gnu.build-id .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.SuSE .note.gnu.build-id
06 .eh_frame_hdr
07
08 .ctors .dtors .jcr .dynamic .got
Dynamic section at offset 0xe58 contains 21 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x400408
0x000000000000000d (FINI) 0x400638
0x0000000000000004 (HASH) 0x4002b0
0x000000006ffffef5 (GNU_HASH) 0x4002d8
0x0000000000000005 (STRTAB) 0x400358
0x0000000000000006 (SYMTAB) 0x4002f8
0x000000000000000a (STRSZ) 61 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x601000
0x0000000000000002 (PLTRELSZ) 48 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x4003d8
0x0000000000000007 (RELA) 0x4003c0
0x0000000000000008 (RELASZ) 24 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x4003a0
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x400396
0x0000000000000000 (NULL) 0x0
Relocation section '.rela.dyn' at offset 0x3c0 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000600ff8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
Relocation section '.rela.plt' at offset 0x3d8 contains 2 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0
000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts#GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main#GLIBC_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table '.symtab' contains 83 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400238 0 SECTION LOCAL DEFAULT 1
2: 0000000000400254 0 SECTION LOCAL DEFAULT 2
3: 0000000000400274 0 SECTION LOCAL DEFAULT 3
4: 000000000040028c 0 SECTION LOCAL DEFAULT 4
5: 00000000004002b0 0 SECTION LOCAL DEFAULT 5
6: 00000000004002d8 0 SECTION LOCAL DEFAULT 6
7: 00000000004002f8 0 SECTION LOCAL DEFAULT 7
8: 0000000000400358 0 SECTION LOCAL DEFAULT 8
9: 0000000000400396 0 SECTION LOCAL DEFAULT 9
10: 00000000004003a0 0 SECTION LOCAL DEFAULT 10
11: 00000000004003c0 0 SECTION LOCAL DEFAULT 11
12: 00000000004003d8 0 SECTION LOCAL DEFAULT 12
13: 0000000000400408 0 SECTION LOCAL DEFAULT 13
14: 0000000000400420 0 SECTION LOCAL DEFAULT 14
15: 0000000000400450 0 SECTION LOCAL DEFAULT 15
16: 0000000000400638 0 SECTION LOCAL DEFAULT 16
17: 0000000000400650 0 SECTION LOCAL DEFAULT 17
18: 0000000000400660 0 SECTION LOCAL DEFAULT 18
19: 0000000000400698 0 SECTION LOCAL DEFAULT 19
20: 0000000000600e30 0 SECTION LOCAL DEFAULT 20
21: 0000000000600e40 0 SECTION LOCAL DEFAULT 21
22: 0000000000600e50 0 SECTION LOCAL DEFAULT 22
23: 0000000000600e58 0 SECTION LOCAL DEFAULT 23
24: 0000000000600ff8 0 SECTION LOCAL DEFAULT 24
25: 0000000000601000 0 SECTION LOCAL DEFAULT 25
26: 0000000000601028 0 SECTION LOCAL DEFAULT 26
27: 0000000000601038 0 SECTION LOCAL DEFAULT 27
28: 0000000000000000 0 SECTION LOCAL DEFAULT 28
29: 0000000000000000 0 SECTION LOCAL DEFAULT 29
30: 0000000000000000 0 SECTION LOCAL DEFAULT 30
31: 0000000000000000 0 SECTION LOCAL DEFAULT 31
32: 0000000000000000 0 SECTION LOCAL DEFAULT 32
33: 0000000000000000 0 SECTION LOCAL DEFAULT 33
34: 0000000000000000 0 SECTION LOCAL DEFAULT 34
35: 0000000000000000 0 SECTION LOCAL DEFAULT 35
36: 0000000000000000 0 SECTION LOCAL DEFAULT 36
37: 0000000000000000 0 SECTION LOCAL DEFAULT 37
38: 0000000000000000 0 SECTION LOCAL DEFAULT 38
39: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c
40: 0000000000000000 0 FILE LOCAL DEFAULT ABS
41: 0000000000000000 0 FILE LOCAL DEFAULT ABS initfini.c
42: 000000000040047c 0 FUNC LOCAL DEFAULT 15 call_gmon_start
43: 0000000000400648 0 NOTYPE LOCAL DEFAULT 16 _real_fini
44: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
45: 0000000000600e30 0 OBJECT LOCAL DEFAULT 20 __CTOR_LIST__
46: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 __DTOR_LIST__
47: 0000000000600e50 0 OBJECT LOCAL DEFAULT 22 __JCR_LIST__
48: 00000000004004a0 0 FUNC LOCAL DEFAULT 15 __do_global_dtors_aux
49: 0000000000601038 1 OBJECT LOCAL DEFAULT 27 completed.6159
50: 0000000000601040 8 OBJECT LOCAL DEFAULT 27 dtor_idx.6161
51: 0000000000400510 0 FUNC LOCAL DEFAULT 15 frame_dummy
52: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
53: 0000000000600e38 0 OBJECT LOCAL DEFAULT 20 __CTOR_END__
54: 0000000000400770 0 OBJECT LOCAL DEFAULT 19 __FRAME_END__
55: 0000000000600e50 0 OBJECT LOCAL DEFAULT 22 __JCR_END__
56: 0000000000400600 0 FUNC LOCAL DEFAULT 15 __do_global_ctors_aux
57: 0000000000000000 0 FILE LOCAL DEFAULT ABS initfini.c
58: 0000000000000000 0 FILE LOCAL DEFAULT ABS 24173361_generating-an-ob
59: 0000000000000000 0 FILE LOCAL DEFAULT ABS elf-init.c
60: 0000000000000000 0 FILE LOCAL DEFAULT ABS
61: 0000000000600e2c 0 NOTYPE LOCAL DEFAULT 20 __init_array_end
62: 0000000000600e58 0 OBJECT LOCAL DEFAULT 23 _DYNAMIC
63: 0000000000600e2c 0 NOTYPE LOCAL DEFAULT 20 __init_array_start
64: 0000000000601000 0 OBJECT LOCAL DEFAULT 25 _GLOBAL_OFFSET_TABLE_
65: 0000000000400560 2 FUNC GLOBAL DEFAULT 15 __libc_csu_fini
66: 0000000000601028 0 NOTYPE WEAK DEFAULT 26 data_start
67: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts##GLIBC_2.2.5
68: 0000000000601038 0 NOTYPE GLOBAL DEFAULT 26 _edata
69: 0000000000400638 16 FUNC GLOBAL DEFAULT 16 _fini
70: 0000000000600e48 0 OBJECT GLOBAL HIDDEN 21 __DTOR_END__
71: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main##GLIBC_
72: 0000000000601028 0 NOTYPE GLOBAL DEFAULT 26 __data_start
73: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
74: 0000000000601030 0 OBJECT GLOBAL HIDDEN 26 __dso_handle
75: 0000000000400650 4 OBJECT GLOBAL DEFAULT 17 _IO_stdin_used
76: 0000000000400570 137 FUNC GLOBAL DEFAULT 15 __libc_csu_init
77: 0000000000601048 0 NOTYPE GLOBAL DEFAULT 27 _end
78: 0000000000400450 0 FUNC GLOBAL DEFAULT 15 _start
79: 0000000000601038 0 NOTYPE GLOBAL DEFAULT 27 __bss_start
80: 000000000040053c 21 FUNC GLOBAL DEFAULT 15 main
81: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
82: 0000000000400408 0 FUNC GLOBAL DEFAULT 13 _init
Histogram for bucket list length (total of 3 buckets):
Length Number % of total Coverage
0 1 ( 33.3%)
1 1 ( 33.3%) 33.3%
2 1 ( 33.3%) 100.0%
Version symbols section '.gnu.version' contains 4 entries:
Addr: 0000000000400396 Offset: 0x000396 Link: 7 (.dynsym)
000: 0 (*local*) 2 (GLIBC_2.2.5) 2 (GLIBC_2.2.5) 0 (*local*)
Version needs section '.gnu.version_r' contains 1 entries:
Addr: 0x00000000004003a0 Offset: 0x0003a0 Link: 8 (.dynstr)
000000: Version: 1 File: libc.so.6 Cnt: 1
0x0010: Name: GLIBC_2.2.5 Flags: none Version: 2
Notes at offset 0x00000254 with length 0x00000020:
Owner Data size Description
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
OS: Linux, ABI: 2.6.4
Notes at offset 0x00000274 with length 0x00000018:
Owner Data size Description
SuSE 0x00000004 Unknown note type: (0x45537553)
Notes at offset 0x0000028c with length 0x00000024:
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 710ef458701fed230f91233a227b7b10c024e2ed
While, that is a lot of detail for such a little file. Here is how to break it down problematically. First, the elf(64) header:
typedef struct elf64_hdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
The secret to creating an elf file is to understand the above structure. This is the first bit of the file your C program must write. Although too lengthy to detail here, you can find this structure in elf.h; which is located (on most Linux systems) here: /usr/include/elf.h.
Related
I'm on linux right now. I'm compiling a super simple C program:
#include <stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
and compiling with
gcc main.c -o main
After running ll to get file sizes, this is what it returns:
-rwxr-xr-x 1 xylight xylight 16K Nov 5 11:30 main
-rw-r--r-- 1 xylight xylight 68 Nov 5 11:23 main.c
-rw-r--r-- 1 xylight xylight 1.5K Nov 5 11:30 main.o
After linking main.o, the file size becomes 16KB! How can I make this smaller? Any linker options?
I'm not sure if this is a duplicate, I couldn't find anything on here. Let me know if it's a duplicate.
After running readelf -h main it says that the ELF type is this: DYN (Shared object file)
Anyone know what I could do to make this smaller?
I wasn't able to find a good explanation of this on SO so let me post one here.
First of all, by default executable includes static symbol table which is used for debugging and is not loaded at runtime. We can get rid of it with strip main which will save us about 2K (down to 15K on my Ubuntu 20).
Now, we can take a closer look at the overheads by running readelf -SW main:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1
[ 2] .note.gnu.property NOTE 0000000000000338 000338 000020 00 A 0 0 8
[ 3] .note.gnu.build-id NOTE 0000000000000358 000358 000024 00 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000037c 00037c 000020 00 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003a0 0003a0 000024 00 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003c8 0003c8 0000a8 18 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000470 000470 000082 00 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000004f2 0004f2 00000e 02 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000500 000500 000020 00 A 7 1 8
[10] .rela.dyn RELA 0000000000000520 000520 0000c0 18 A 6 0 8
[11] .rela.plt RELA 00000000000005e0 0005e0 000018 18 AI 6 24 8
[12] .init PROGBITS 0000000000001000 001000 00001b 00 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 001020 000020 10 AX 0 0 16
[14] .plt.got PROGBITS 0000000000001040 001040 000010 10 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000001050 001050 000010 10 AX 0 0 16
[16] .text PROGBITS 0000000000001060 001060 000185 00 AX 0 0 16
[17] .fini PROGBITS 00000000000011e8 0011e8 00000d 00 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 002000 000012 00 A 0 0 4
[19] .eh_frame_hdr PROGBITS 0000000000002014 002014 000044 00 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002058 002058 000108 00 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003db8 002db8 000008 08 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003dc0 002dc0 000008 08 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003dc8 002dc8 0001f0 10 WA 7 0 8
[24] .got PROGBITS 0000000000003fb8 002fb8 000048 08 WA 0 0 8
[25] .data PROGBITS 0000000000004000 003000 000010 00 WA 0 0 8
[26] .bss NOBITS 0000000000004010 003010 000008 00 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 003010 00002a 01 MS 0 0 1
[28] .shstrtab STRTAB 0000000000000000 00303a 00010a 00 0 0 1
As you can see the first 1.5K (up to, but not including, the .init) hold ELF header and bookkeeping data for loading shared libraries (all those .gnu.hash, .dynsym, etc.).
This is followed by 500 bytes of code (.init, .plt, etc. up to, but not including, the .rodata). Note that code allocation starts at 4K page boundary so we waste 2.5K for padding.
Then 3.5K is wasted to realign code at 4K page boundary before ~1K of data sections (.rodata, unwinding tables, etc.). There is an interesting waste of 3K between .eh_frame and .init_array which happens due to some weird alignment between readonly and normal data (see this question for more details).
So to summarize, only a small fraction of ELF size (1.5+0.5+1=3K i.e. 20%) is really used and the rest is wasted to properly align addresses when ELF is mmaped to memory. Address alignment is needed so that dynamic loader could assign different permissions for memory pages (e.g. code pages can not be written but can be executed and for data pages permissions are reversed).
I'm trying to use the command readelf -S libtest.so on the 32bit libtest.so which compiled with clang11 --target=arm-linux-androideabi21 -march=armv7-a & cflags -funwind-table -fno-exceptions.
The .eh_frame or .eh_frame_hdr segment can not be found in the output.
However,it is surely exist in the 64-bit .so(compiled with --target=aarch64-linux-android21). Does anyone known the reason?
32bit:
---------------------------------------------------------------------------------
There are 29 section headers, starting at offset 0x2c3c6b8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00000174 000174 000013 00 A 0 0 1
[ 2] .note.android.ide NOTE 00000188 000188 000098 00 A 0 0 4
[ 3] .note.crashpad.in NOTE 00000220 000220 00001c 00 A 0 0 4
[ 4] .note.gnu.build-i NOTE 0000023c 00023c 000024 00 A 0 0 4
[ 5] .dynsym DYNSYM 00000260 000260 005550 10 A 10 1 4
[ 6] .gnu.version VERSYM 000057b0 0057b0 000aaa 02 A 5 0 2
[ 7] .gnu.version_r VERNEED 0000625c 00625c 000060 00 A 10 3 4
[ 8] .gnu.hash GNU_HASH 000062bc 0062bc 001a14 00 A 5 0 4
[ 9] .hash HASH 00007cd0 007cd0 002ab0 04 A 5 0 4
[10] .dynstr STRTAB 0000a780 00a780 016bf6 00 A 0 0 1
[11] .rel.dyn LOOS+0x1 00021378 021378 0297f6 01 A 5 0 4
[12] .ARM.exidx ARM_EXIDX 0004ab70 04ab70 1be028 00 AL 16 0 4
[13] .rel.plt REL 00208b98 208b98 000db0 08 A 5 23 4
[14] .rodata PROGBITS 00209a00 209a00 55b9ac 00 AMS 0 0 256
[15] .ARM.extab PROGBITS 007653ac 7653ac 005d04 00 A 0 0 4
[16] .text PROGBITS 0076b0c0 76b0c0 22e96f4 00 AX 0 0 64
[17] .plt PROGBITS 02a547c0 2a547c0 001b80 00 AX 0 0 16
[18] .fini_array FINI_ARRAY 02a57340 2a56340 000008 00 WA 0 0 4
[19] .data.rel.ro PROGBITS 02a57348 2a56348 1c300c 00 WA 0 0 8
[20] .init_array INIT_ARRAY 02c1a354 2c19354 000018 00 WA 0 0 4
[21] .dynamic DYNAMIC 02c1a36c 2c1936c 000100 08 WA 10 0 4
[22] .got PROGBITS 02c1a46c 2c1946c 000298 00 WA 0 0 4
[23] .got.plt PROGBITS 02c1a704 2c19704 0006e4 00 WA 0 0 4
[24] .bss.rel.ro NOBITS 02c1ade8 2c19de8 000000 00 WA 0 0 1
[25] .data PROGBITS 02c1bde8 2c19de8 022624 00 WA 0 0 8
[26] .bss NOBITS 02c3e410 2c3c40c 439c3c 00 WA 0 0 16
[27] .comment PROGBITS 00000000 2c3c40c 000193 01 MS 0 0 1
[28] .shstrtab STRTAB 00000000 2c3c59f 000116 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)
---------------------------------------------------------------------------------
64bit:
---------------------------------------------------------------------------------
There are 28 section headers, starting at offset 0x59b4b30:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.android.ide NOTE 0000000000000238 00000238
0000000000000098 0000000000000000 A 0 0 4
[ 2] .note.crashpad.in NOTE 00000000000002d0 000002d0
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.build-i NOTE 00000000000002f0 000002f0
0000000000000024 0000000000000000 A 0 0 4
[ 4] .dynsym DYNSYM 0000000000000318 00000318
0000000000007cb0 0000000000000018 A 9 1 8
[ 5] .gnu.version VERSYM 0000000000007fc8 00007fc8
0000000000000a64 0000000000000002 A 4 0 2
[ 6] .gnu.version_r VERNEED 0000000000008a2c 00008a2c
0000000000000060 0000000000000000 A 9 3 4
[ 7] .gnu.hash GNU_HASH 0000000000008a90 00008a90
00000000000018e0 0000000000000000 A 4 0 8
[ 8] .hash HASH 000000000000a370 0000a370
0000000000002998 0000000000000004 A 4 0 4
[ 9] .dynstr STRTAB 000000000000cd08 0000cd08
000000000001949f 0000000000000000 A 0 0 1
[10] .rela.dyn LOOS+0x2 00000000000261a8 000261a8
0000000000137999 0000000000000001 A 4 0 8
[11] .rela.plt RELA 000000000015db48 0015db48
0000000000002af0 0000000000000018 AI 4 24 8
[12] .rodata PROGBITS 0000000000160700 00160700
00000000006e0d98 0000000000000000 AMS 0 0 256
[13] .gcc_except_table PROGBITS 0000000000841498 00841498
0000000000000f84 0000000000000000 A 0 0 4
[14] .eh_frame_hdr PROGBITS 000000000084241c 0084241c
00000000003539c4 0000000000000000 A 0 0 4
[15] .eh_frame PROGBITS 0000000000b95de0 00b95de0
0000000000d5494c 0000000000000000 A 0 0 8
[16] .text PROGBITS 00000000018ea740 018ea740
0000000003cb336c 0000000000000000 AX 0 0 64
[17] malloc_hook PROGBITS 000000000559daac 0559daac
00000000000000c8 0000000000000000 AX 0 0 2
[18] .plt PROGBITS 000000000559db80 0559db80
0000000000001cc0 0000000000000000 AX 0 0 16
[19] .data.rel.ro PROGBITS 00000000055a0840 0559f840
00000000003a4d48 0000000000000000 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000005945588 05944588
0000000000000010 0000000000000008 WA 0 0 8
[21] .init_array INIT_ARRAY 0000000005945598 05944598
0000000000000020 0000000000000000 WA 0 0 8
[22] .dynamic DYNAMIC 00000000059455b8 059445b8
0000000000000200 0000000000000010 WA 9 0 8
[23] .got PROGBITS 00000000059457b8 059447b8
000000000001c578 0000000000000000 WA 0 0 8
[24] .got.plt PROGBITS 0000000005961d30 05960d30
0000000000000e68 0000000000000000 WA 0 0 8
[25] .data PROGBITS 0000000005963b98 05961b98
0000000000052e78 0000000000000000 WA 0 0 8
[26] .bss NOBITS 00000000059b6a40 059b4a10
00000000004cbb40 0000000000000000 WA 0 0 64
[27] .shstrtab STRTAB 0000000000000000 059b4a10
000000000000011b 0000000000000000 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),
p (processor specific)
---------------------------------------------------------------------------------
I found the size different between -funwind-table and -fno-unwind-table in arm32's libtest.so:
-funwind-table:
FILE SIZE VM SIZE
-------------- --------------
5.2% 2.77Mi 4.8% 2.77Mi .ARM.exidx
0.0% 25.6Ki 0.0% 25.6Ki .ARM.extab
-fno-unwind-table:
FILE SIZE VM SIZE
-------------- --------------
0.0% 5.36Ki 0.0% 5.36Ki .ARM.exidx
0.0% 5.62Ki 0.0% 5.62Ki .ARM.extab
so, the unwind-table info of arm32 is in .ARM.exidx/.ARM.extab, not the same with .eh_frame/.eh_frame_hdr in arm64.
The multiboot2 header can't be found in my final ELF, because inside the binary file it stands at offset 0x334e0, but the multiboot2 spec tells only the first 32KiB, i.e. 0x8000 bytes, are checked. Therefore it comes "too late".
I don't know how I can solve this. Is the ELF header too bloated? The multiboot2 header itself is correct, i.e. several tools to check multiboot2 headers tell it is correct. It is only not working, when I link the header together with the other code. If I adjust tools to verify multiboot2 headers, i.e. bootimage[1] to look at more than the first 32KiB, it works too.
My linker script (for GNU ld):
/** The "start"-symbol from start.asm. */
ENTRY(start)
SECTIONS {
/* Multiboot2-Header must be 64-bit (8 byte) aligned according to spec. */
. = ALIGN(8);
.multiboot2_header :
{
/* ensure that the multiboot header is at the beginning */
*(.multiboot2_header)
}
.text :
{
*(.text)
}
}
readelf -WSl <my-elf> tells, that the .multiboot2_header section is indeed the first one:
There are 1526 section headers, starting at offset 0x3ca8d8:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .multiboot2_header PROGBITS 0000000000000000 0334e8 000048 00 0 0 8
[ 2] .debug_abbrev PROGBITS 0000000000000000 033530 00ecea 00 0 0 1
[ 3] .debug_info PROGBITS 0000000000000000 04221a 0f0391 00 0 0 1
[ 4] .debug_aranges PROGBITS 0000000000000000 1325ab 019f40 00 0 0 1
[ 5] .debug_ranges PROGBITS 0000000000000000 14c4eb 0301d0 00 0 0 1
[ 6] .debug_str PROGBITS 0000000000000000 17c6bb 0c5de1 01 MS 0 0 1
[ 7] .debug_pubnames PROGBITS 0000000000000000 24249c 035215 00 0 0 1
[ 8] .debug_pubtypes PROGBITS 0000000000000000 2776b1 058c44 00 0 0 1
[ 9] .debug_frame PROGBITS 0000000000000000 2d02f8 033b60 00 0 0 8
[10] .debug_line PROGBITS 0000000000000000 303e58 08390a 00 0 0 1
[11] .debug_loc PROGBITS 0000000000000000 387762 0038d8 00 0 0 1
[12] .comment PROGBITS 0000000000000000 38b03a 000013 01 MS 0 0 1
[13] .symtab SYMTAB 0000000000000000 38b050 0089d0 18 15 803 8
[14] .shstrtab STRTAB 0000000000000000 393a20 01cec9 00 0 0 1
[15] .strtab STRTAB 0000000000000000 3b08e9 019fee 00 0 0 1
[16] .rodata._ZN137_$LT$rust_multiboot2_64_bit_kernel..logger..BootStageAwareLogger$u20$as$u20$rust_multiboot2_64_bit_kernel..boot_stage..BootStageAware$GT$15next_boot_stage17h5918ecf04a4f1232E PROGBITS 0000000000000000 000160 000010 00 A 0 0 4
...
[179] .rodata..L__unnamed_94 PROGBITS 00000000000045a8 004708 00007f 00 A 0 0 1
[180] .eh_frame_hdr PROGBITS 0000000000004628 004788 00000c 00 A 0 0 4
[181] .eh_frame PROGBITS 0000000000004638 004798 00001c 00 A 0 0 8
[182] .text PROGBITS 0000000000004654 0047b4 00001b 00 AX 0 0 4
[183] .text._ZN29rust_multiboot2_64_bit_kernel6logger20BootStageAwareLogger13apply_to_each17h77f9f12abd1f054eE PROGBITS 0000000000004670 0047d0 000130 00 AX 0 0 16
...
[1388] .text._ZN54_$LT$u32$u20$as$u20$core..ops..bit..Shl$LT$i32$GT$$GT$3shl17h0ba8101e5b58ae12E PROGBITS 0000000000030390 0304f0 000049 00 AX 0 0 16
[1389] .text._ZN58_$LT$$RF$u32$u20$as$u20$core..ops..bit..Shl$LT$i32$GT$$GT$3shl17h518033907a793365E PROGBITS 00000000000303e0 030540 000021 00 AX 0 0 16
[1390] .text.memcpy PROGBITS 0000000000030410 030570 00004e 00 AX 0 0 16
[1391] .text.memset PROGBITS 0000000000030460 0305c0 0000a4 00 AX 0 0 16
[1392] .text.memcmp PROGBITS 0000000000030510 030670 000179 00 AX 0 0 16
[1393] .data.rel.ro..L__unnamed_1 PROGBITS 0000000000030690 0307f0 0002c0 00 WA 0 0 8
[1394] .data.rel.ro..L__unnamed_2 PROGBITS 0000000000030950 030ab0 000300 00 WA 0 0 8
...
[1515] .data.rel.ro..L__unnamed_169 PROGBITS 00000000000332e0 033440 000018 00 WA 0 0 8
[1516] .got PROGBITS 00000000000332f8 033458 000090 00 WA 0 0 8
[1517] .bss._ZN29rust_multiboot2_64_bit_kernel6logger6LOGGER17h0a7e2a9a53f2b5ddE NOBITS 0000000000033388 0334e8 000018 00 WA 0 0 8
[1518] .bss NOBITS 00000000000333a0 0334e8 020000 00 WA 0 0 8
[1519] .bss._ZN29rust_multiboot2_64_bit_kernel3mb225MULTIBOOT2_INFO_STRUCTURE17h67db2667e3bd19ceE NOBITS 00000000000533a0 0334e8 000018 00 WA 0 0 8
[1520] .bss._ZN29rust_multiboot2_64_bit_kernel5panic13PANIC_HANDLER17h02bbbbc17c579b55E NOBITS 00000000000533b8 0334e8 00000c 00 WA 0 0 4
[1521] .bss._ZN29rust_multiboot2_64_bit_kernel5xuefi10UEFI_ST_BS17ha7c24b049d2b76abE NOBITS 00000000000533c8 0334e8 000008 00 WA 0 0 8
[1522] .bss._ZN29rust_multiboot2_64_bit_kernel10boot_stage10BOOT_STAGE17he05c77811885a1c6E NOBITS 00000000000533d0 0334e8 000001 00 WA 0 0 1
[1523] .bss._ZN29rust_multiboot2_64_bit_kernel11kernelalloc9ALLOCATOR17h93bce260f0439187E NOBITS 00000000000533d1 0334e8 000001 00 WA 0 0 1
[1524] .bss._ZN3log5STATE17hdfa5c64bc29aed3eE NOBITS 00000000000533d8 0334e8 000008 00 WA 0 0 8
[1525] .bss._ZN3log20MAX_LOG_LEVEL_FILTER17h84bf10c3ec44ab54E NOBITS 00000000000533e0 0334e8 000008 00 WA 0 0 8
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),
l (large), p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x4654
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000160 0x0000000000000000 0x0000000000000000 0x004654 0x004654 R 0x10
LOAD 0x0047b4 0x0000000000004654 0x0000000000004654 0x02c035 0x02c035 R E 0x10
LOAD 0x0307f0 0x0000000000030690 0x0000000000030690 0x002cf8 0x022d58 RW 0x8
GNU_EH_FRAME 0x004788 0x0000000000004628 0x0000000000004628 0x00000c 0x00000c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0
Section to Segment mapping:
Segment Sections...
00 .rodata._ZN137_$LT$rust_multib...
01 .text .text._ZN29rust_multiboot2_64_bit_kernel6logger2...
02 .data.rel.ro..L__unnamed_1 .data.rel.ro..L__unnamed_2 ...
03 .eh_frame_hdr
04
There you can see the header comes "too late" in the file. How can I solve this? How can I move it to a smaller offset in the ELF file, i.e. closer to the file begin?
PS: The ELF get's assembled by cargo/rustc/llvm, which uses GNU ld with a custom link script in my case.
Section to Segment mapping:
Segment Sections...
00 .rodata._ZN137_$LT$rust_multib...
01 .text .text._ZN29rust_multiboot2_64_bit_kernel6logger2...
...
It's clear that the .rodata._ZN.... sections are at lower offsets in the file, and the .text is not in fact the very first.
You need to move .rodata... into a separate segment (by adjusting the linker script), or you need to disable separate RO segment for the ELF header (which would allow .text to be in the first segment). See this answer.
readelf output of the object file:
Symbol table '.symtab' contains 15 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS fp16.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 NOTYPE LOCAL DEFAULT 1 $t
6: 00000001 194 FUNC LOCAL DEFAULT 1 __gnu_f2h_internal
7: 00000010 0 NOTYPE LOCAL DEFAULT 5 $d
8: 00000000 0 SECTION LOCAL DEFAULT 5
9: 00000000 0 SECTION LOCAL DEFAULT 7
10: 000000c5 78 FUNC GLOBAL HIDDEN 1 __gnu_h2f_internal
11: 00000115 4 FUNC GLOBAL HIDDEN 1 __gnu_f2h_ieee
12: 00000119 4 FUNC GLOBAL HIDDEN 1 __gnu_h2f_ieee
13: 0000011d 4 FUNC GLOBAL HIDDEN 1 __gnu_f2h_alternative
14: 00000121 4 FUNC GLOBAL HIDDEN 1 __gnu_h2f_alternative
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 000124 00 AX 0 0 4
[ 2] .rel.text REL 00000000 00058c 000010 08 9 1 4
[ 3] .data PROGBITS 00000000 000158 000000 00 WA 0 0 1
[ 4] .bss NOBITS 00000000 000158 000000 00 WA 0 0 1
[ 5] .debug_frame PROGBITS 00000000 000158 00008c 00 0 0 4
[ 6] .rel.debug_frame REL 00000000 00059c 000060 08 9 5 4
[ 7] .ARM.attributes ARM_ATTRIBUTES 00000000 0001e4 00002f 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 000213 000051 00 0 0 1
[ 9] .symtab SYMTAB 00000000 00041c 0000f0 10 10 10 4
[10] .strtab STRTAB 00000000 00050c 00007e 00 0 0 1
Relocation section '.rel.text' at offset 0x58c contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0000011a 00000a66 R_ARM_THM_JUMP11 000000c5 __gnu_h2f_internal
00000122 00000a66 R_ARM_THM_JUMP11 000000c5 __gnu_h2f_internal
Relocation section '.rel.debug_frame' at offset 0x59c contains 12 entries:
Offset Info Type Sym.Value Sym. Name
00000014 00000802 R_ARM_ABS32 00000000 .debug_frame
00000018 00000202 R_ARM_ABS32 00000000 .text
00000040 00000802 R_ARM_ABS32 00000000 .debug_frame
00000044 00000202 R_ARM_ABS32 00000000 .text
00000050 00000802 R_ARM_ABS32 00000000 .debug_frame
00000054 00000202 R_ARM_ABS32 00000000 .text
00000060 00000802 R_ARM_ABS32 00000000 .debug_frame
00000064 00000202 R_ARM_ABS32 00000000 .text
00000070 00000802 R_ARM_ABS32 00000000 .debug_frame
00000074 00000202 R_ARM_ABS32 00000000 .text
00000080 00000802 R_ARM_ABS32 00000000 .debug_frame
00000084 00000202 R_ARM_ABS32 00000000 .text
.text section structure as I understand it:
.text section has size of 0x124
0x0: unknown byte
0x1-0xC3: __gnu_f2h_internal
0xC3-0xC5: two unknown bytes between those functions (btw what are those?)
0xC5-0x113: __gnu_h2f_internal
0x113-0x115: two unknown bytes between those functions
0x115-0x119: __gnu_f2h_ieee
0x119-0x11D: __gnu_h2f_ieee
0x11D-0x121: __gnu_f2h_alternative
0x121-0x125: __gnu_h2f_alternative // section is only 0x124, what happened to the missing byte?
Notice that the section size is 0x124 and the last function end in 0x125, what happend to the missing byte?
Thanks.
Technically, your "missing byte" is the one right there at 0x0.
Note that you're looking at the value of the symbol, i.e. the runtime function address (this would be a lot clearer if your .text section VMA wasn't 0). Since they're Thumb functions, the addresses have bit 0 set such that the processor will switch to Thumb mode when calling them; the actual locations of those instructions are still halfword-aligned, i.e. 0x0, 0xc4, 0x114, etc. since they couldn't be executed otherwise (you'd take a fault for a misaligned PC). Strip off bit 0 as per what the ARM
ELF spec says about STT_FUNC symbols to get the actual VMA of the instruction corresponding to that symbol, then subtract the start of the section and you should have the same relative offset as within the object file itself.
<offset in section> = (<symbol value> & ~1) - <section VMA>
The extra halfword padding after some functions just ensures each symbol is word-aligned - there are probably various reasons for this, but the first one that comes to mind is that the adr instruction wouldn't work properly if they weren't.
readelf output of the object file:
Symbol table '.symtab' contains 15 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS fp16.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 NOTYPE LOCAL DEFAULT 1 $t
6: 00000001 194 FUNC LOCAL DEFAULT 1 __gnu_f2h_internal
7: 00000010 0 NOTYPE LOCAL DEFAULT 5 $d
8: 00000000 0 SECTION LOCAL DEFAULT 5
9: 00000000 0 SECTION LOCAL DEFAULT 7
10: 000000c5 78 FUNC GLOBAL HIDDEN 1 __gnu_h2f_internal
11: 00000115 4 FUNC GLOBAL HIDDEN 1 __gnu_f2h_ieee
12: 00000119 4 FUNC GLOBAL HIDDEN 1 __gnu_h2f_ieee
13: 0000011d 4 FUNC GLOBAL HIDDEN 1 __gnu_f2h_alternative
14: 00000121 4 FUNC GLOBAL HIDDEN 1 __gnu_h2f_alternative
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 000124 00 AX 0 0 4
[ 2] .rel.text REL 00000000 00058c 000010 08 9 1 4
[ 3] .data PROGBITS 00000000 000158 000000 00 WA 0 0 1
[ 4] .bss NOBITS 00000000 000158 000000 00 WA 0 0 1
[ 5] .debug_frame PROGBITS 00000000 000158 00008c 00 0 0 4
[ 6] .rel.debug_frame REL 00000000 00059c 000060 08 9 5 4
[ 7] .ARM.attributes ARM_ATTRIBUTES 00000000 0001e4 00002f 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 000213 000051 00 0 0 1
[ 9] .symtab SYMTAB 00000000 00041c 0000f0 10 10 10 4
[10] .strtab STRTAB 00000000 00050c 00007e 00 0 0 1
Relocation section '.rel.text' at offset 0x58c contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0000011a 00000a66 R_ARM_THM_JUMP11 000000c5 __gnu_h2f_internal
00000122 00000a66 R_ARM_THM_JUMP11 000000c5 __gnu_h2f_internal
Relocation section '.rel.debug_frame' at offset 0x59c contains 12 entries:
Offset Info Type Sym.Value Sym. Name
00000014 00000802 R_ARM_ABS32 00000000 .debug_frame
00000018 00000202 R_ARM_ABS32 00000000 .text
00000040 00000802 R_ARM_ABS32 00000000 .debug_frame
00000044 00000202 R_ARM_ABS32 00000000 .text
00000050 00000802 R_ARM_ABS32 00000000 .debug_frame
00000054 00000202 R_ARM_ABS32 00000000 .text
00000060 00000802 R_ARM_ABS32 00000000 .debug_frame
00000064 00000202 R_ARM_ABS32 00000000 .text
00000070 00000802 R_ARM_ABS32 00000000 .debug_frame
00000074 00000202 R_ARM_ABS32 00000000 .text
00000080 00000802 R_ARM_ABS32 00000000 .debug_frame
00000084 00000202 R_ARM_ABS32 00000000 .text
.text section structure as I understand it:
.text section has size of 0x124
0x0: unknown byte
0x1-0xC3: __gnu_f2h_internal
0xC3-0xC5: two unknown bytes between those functions (btw what are those?)
0xC5-0x113: __gnu_h2f_internal
0x113-0x115: two unknown bytes between those functions
0x115-0x119: __gnu_f2h_ieee
0x119-0x11D: __gnu_h2f_ieee
0x11D-0x121: __gnu_f2h_alternative
0x121-0x125: __gnu_h2f_alternative // section is only 0x124, what happened to the missing byte?
Notice that the section size is 0x124 and the last function end in 0x125, what happend to the missing byte?
Thanks.
Technically, your "missing byte" is the one right there at 0x0.
Note that you're looking at the value of the symbol, i.e. the runtime function address (this would be a lot clearer if your .text section VMA wasn't 0). Since they're Thumb functions, the addresses have bit 0 set such that the processor will switch to Thumb mode when calling them; the actual locations of those instructions are still halfword-aligned, i.e. 0x0, 0xc4, 0x114, etc. since they couldn't be executed otherwise (you'd take a fault for a misaligned PC). Strip off bit 0 as per what the ARM
ELF spec says about STT_FUNC symbols to get the actual VMA of the instruction corresponding to that symbol, then subtract the start of the section and you should have the same relative offset as within the object file itself.
<offset in section> = (<symbol value> & ~1) - <section VMA>
The extra halfword padding after some functions just ensures each symbol is word-aligned - there are probably various reasons for this, but the first one that comes to mind is that the adr instruction wouldn't work properly if they weren't.