LOAD segment with RWX permissions, Linker add writable attribute after use align in section - linker

My binutils version:
GNU ld (GNU Binutils) 2.39
and there is a new warn 'LOAD segment with RWX permissions'
here is the linker script
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
/* Fake ROM area */
rom (rxa) : ORIGIN = 0x80000000, LENGTH = 512K
ram (wxa) : ORIGIN = 0x80080000, LENGTH = 512K
}
SECTIONS
{
.init :
{
_text = .;
KEEP (*(SORT_NONE(.init)))
} >rom AT>rom
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >rom AT>rom
.fini :
{
KEEP (*(SORT_NONE(.fini)))
_etext = .;
} >rom AT>rom
.rodata.align :
{
. = ALIGN(4);
_rodata = .;
} >rom AT>rom
.rodata.start :
{
_rodata_lma = LOADADDR(.rodata.start);
} >rom AT>rom
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
. = ALIGN(4);
_erodata = .;
} >rom AT>rom
.data.align :
{
. = ALIGN(4);
_data = .;
} >ram AT>rom
.data.start :
{
_data_lma = LOADADDR(.data.start);
} >ram AT>rom
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.sdata2 .sdata2.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
_edata = .;
} >ram AT>rom
.bss.align :
{
. = ALIGN(4);
_bss = .;
} >ram AT>rom
.bss.start :
{
_bss_lma = LOADADDR(.bss.start);
} >ram AT>rom
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT>rom
. = ALIGN(8);
_end = .;
.stack :
{
. = ALIGN(16);
. += __stack_size;
_stack_top = .;
} >ram AT>ram
}
I found that if I change the rodata.align section as below, the problem can fix.
.rodata.align ALIGN(4):
{
_rodata = .;
} >rom AT>rom
readelf -Sl original.elf
There are 24 section headers, starting at offset 0x29a08:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .init PROGBITS 80000000 001000 000076 00 AX 0 0 1
[ 2] .text PROGBITS 80000100 001100 00b6f2 00 AX 0 0 256
[ 3] .rodata.align NOBITS 8000b7f2 00c7f2 000002 00 WA 0 0 1
[ 4] .rodata PROGBITS 8000b7f4 00c7f4 0009c4 00 A 0 0 4
[ 5] .data.align PROGBITS 80080000 00e9d0 000000 00 WA 0 0 1
[ 6] .data PROGBITS 80080000 00e000 0009d0 00 WA 0 0 8
[ 7] .bss.align NOBITS 800809d0 000000 000000 00 WA 0 0 1
[ 8] .bss NOBITS 800809d0 00e9d0 011e08 00 WA 0 0 16
[ 9] .stack NOBITS 800927d8 00f7d8 000134 00 WA 0 0 1
[10] .comment PROGBITS 00000000 00e9d0 00002d 01 MS 0 0 1
[11] .riscv.attributes RISCV_ATTRIBUTE 00000000 00e9fd 00002f 00 0 0 1
[12] .debug_info PROGBITS 00000000 00ea2c 003a54 00 0 0 1
[13] .debug_abbrev PROGBITS 00000000 012480 0010bc 00 0 0 1
[14] .debug_loclists PROGBITS 00000000 01353c 0097da 00 0 0 1
[15] .debug_aranges PROGBITS 00000000 01cd16 000178 00 0 0 1
[16] .debug_rnglists PROGBITS 00000000 01ce8e 001154 00 0 0 1
[17] .debug_line PROGBITS 00000000 01dfe2 007949 00 0 0 1
[18] .debug_str PROGBITS 00000000 02592b 0008ed 01 MS 0 0 1
[19] .debug_line_str PROGBITS 00000000 026218 000388 01 MS 0 0 1
[20] .debug_frame PROGBITS 00000000 0265a0 000288 00 0 0 4
[21] .symtab SYMTAB 00000000 026828 002020 10 22 343 4
[22] .strtab STRTAB 00000000 028848 0010bf 00 0 0 1
[23] .shstrtab STRTAB 00000000 029907 0000fe 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),
D (mbind), p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x80000000
There are 4 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
RISCV_ATTRIBUT 0x00e9fd 0x00000000 0x00000000 0x0002f 0x00000 R 0x1
LOAD 0x001000 0x80000000 0x80000000 0x0c1b8 0x0c1b8 RWE 0x1000
LOAD 0x00e000 0x80080000 0x8000c1b8 0x009d0 0x127d8 RW 0x1000
LOAD 0x0007d8 0x800927d8 0x800927d8 0x00000 0x00134 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .riscv.attributes
01 .init .text .rodata.align .rodata
02 .data .bss.align .bss
03 .stack
readelf -Sl modify.elf
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .init PROGBITS 80000000 001000 000076 00 AX 0 0 1
[ 2] .text PROGBITS 80000100 001100 00b6f2 00 AX 0 0 256
[ 3] .rodata PROGBITS 8000b7f4 00c7f4 0009c4 00 A 0 0 4
[ 4] .data.align PROGBITS 80080000 00e9d0 000000 00 WA 0 0 1
[ 5] .data PROGBITS 80080000 00e000 0009d0 00 WA 0 0 8
[ 6] .bss.align NOBITS 800809d0 000000 000000 00 WA 0 0 1
[ 7] .bss NOBITS 800809d0 00e9d0 011e08 00 WA 0 0 16
[ 8] .stack NOBITS 800927d8 00f7d8 000134 00 WA 0 0 1
[ 9] .comment PROGBITS 00000000 00e9d0 00002d 01 MS 0 0 1
[10] .riscv.attributes RISCV_ATTRIBUTE 00000000 00e9fd 00002f 00 0 0 1
[11] .debug_info PROGBITS 00000000 00ea2c 003a54 00 0 0 1
[12] .debug_abbrev PROGBITS 00000000 012480 0010bc 00 0 0 1
[13] .debug_loclists PROGBITS 00000000 01353c 0097da 00 0 0 1
[14] .debug_aranges PROGBITS 00000000 01cd16 000178 00 0 0 1
[15] .debug_rnglists PROGBITS 00000000 01ce8e 001154 00 0 0 1
[16] .debug_line PROGBITS 00000000 01dfe2 007949 00 0 0 1
[17] .debug_str PROGBITS 00000000 02592b 0008ed 01 MS 0 0 1
[18] .debug_line_str PROGBITS 00000000 026218 000388 01 MS 0 0 1
[19] .debug_frame PROGBITS 00000000 0265a0 000288 00 0 0 4
[20] .symtab SYMTAB 00000000 026828 002010 10 21 342 4
[21] .strtab STRTAB 00000000 028838 0010bf 00 0 0 1
[22] .shstrtab STRTAB 00000000 0298f7 0000f0 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),
D (mbind), p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x80000000
There are 4 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
RISCV_ATTRIBUT 0x00e9fd 0x00000000 0x00000000 0x0002f 0x00000 R 0x1
LOAD 0x001000 0x80000000 0x80000000 0x0c1b8 0x0c1b8 R E 0x1000
LOAD 0x00e000 0x80080000 0x8000c1b8 0x009d0 0x127d8 RW 0x1000
LOAD 0x0007d8 0x800927d8 0x800927d8 0x00000 0x00134 RW 0x1000
Why the align command cause the LOAD section has a writable attribute?
I found that if I change the rodata.align section as below, the problem can fix.
.rodata.align ALIGN(4):
{
_rodata = .;
} >rom AT>rom

Related

Why .eh_frame and .eh_frame_hdr does not exist in the clang 32bit so?

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.

multiboot2 header comes "too late" in ELF file (to large offset), even if it is the very first section

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.

Differences between GCC/Clang when linking

Because of vastly better C++ compile times I've recently added the option to compile a project for an ARM Cortex-M4 microcontroller with Clang instead of the arm-none-eabi-gcc toolchain. The whole process ran quite smoothly and I quickly had working ELF and HEX files. It wasn't until yesterday evening that I noticed that the ELF files actually differ quite a lot...
Before I continue let's inspect the ELF produced by GCC to get some kind of baseline.
GCC's ELF contains the following sections (apart from debug stuff)
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .vector_table PROGBITS 08000000 010000 000010 00 A 0 0 4
[ 2] .version NOBITS 08000010 010010 000010 00 WA 0 0 1
[ 3] .text PROGBITS 08000020 010020 000138 00 AX 0 0 4
[ 4] .rodata PROGBITS 08000158 010158 000000 00 WA 0 0 1
[ 5] .data PROGBITS 20000000 010158 000000 00 WA 0 0 1
[ 6] .data2 PROGBITS 10000000 010158 000000 00 W 0 0 1
[ 7] .bss NOBITS 20000000 020000 00038c 00 WA 0 0 512
[ 8] .bss2 PROGBITS 2000038c 010158 000000 00 W 0 0 1
[ 9] ._user_heap_stack NOBITS 2000038c 020000 000e04 00 WA 0 0 1
But despite .data and .bss being marked with an "A" (alloc) flag only loads the following
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010000 0x08000000 0x08000000 0x00158 0x00158 RWE 0x10000
LOAD 0x000000 0x20000000 0x20000000 0x00000 0x01190 RW 0x10000
Section to Segment mapping:
Segment Sections...
00 .vector_table .version .text
01 .bss ._user_heap_stack
So far so good.
The problem emerged when I tried to create binaries from an ELF produced by Clang. Those files where huge in size (256MB) which is nowhere near what I had expected. Now, if you're not familiar with ARM microcontrollers, they usually contain FLASH and RAM memory at very different address locations (e.g. 0x0800'0000 for FLASH and 0x2000'0000 for RAM as seen above). So I already had some suspicion on what's going on... I checked my linker script and put a NOLOAD directive on every section which goes solely to RAM. Problem solved?
Well... not really. In fact my binaries grew even bigger.
Let's take a look at Clang's ELF. It's bugging me a little that Clang doesn't seem to remove the section for unwinding (ARM.exidx) although I compile with -fno-unwind-tables and -gc-sections but ok, I can live with those 16B.
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .vector_table PROGBITS 08000000 001000 000010 00 A 0 0 4
[ 2] .version PROGBITS 08000010 001010 000010 00 A 0 0 1
[ 3] .text PROGBITS 08000020 001020 000334 00 AX 0 0 4
[ 4] .rodata PROGBITS 08000354 001354 000000 00 AX 0 0 1
[ 5] .ARM.exidx ARM_EXIDX 08000354 001354 000010 00 AL 3 0 4
[ 6] .preinit_array PROGBITS 08000364 001364 000000 00 A 0 0 1
[ 7] .init_array INIT_ARRAY 08000364 001364 000004 04 WA 0 0 4
[ 8] .fini_array FINI_ARRAY 08000368 001368 000004 04 WA 0 0 4
[ 9] .data PROGBITS 20000000 002000 000000 00 WA 0 0 1
[10] .data2 PROGBITS 10000000 002000 000000 00 WA 0 0 1
[11] .bss NOBITS 20000000 002000 0001ac 00 WA 0 0 512
[12] .bss2 PROGBITS 200001ac 002000 000000 00 WA 0 0 1
[13] ._user_heap_stack PROGBITS 200001ac 002000 000e04 00 WA 0 0 1
Now this is where it gets interesting and where I have no clue whats happening. What is GNU_RELRO and GNU_STACK and how does it end up there? Why is GNU_STACK at address 0. Any chance this entry is bloating my binaries?
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x08000000 0x08000000 0x00364 0x00364 R E 0x1000
LOAD 0x001364 0x08000364 0x08000364 0x00008 0x00008 RW 0x1000
GNU_RELRO 0x001364 0x08000364 0x08000364 0x00008 0x00c9c R 0x1
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0
EXIDX 0x001354 0x08000354 0x08000354 0x00010 0x00010 R 0x4
Section to Segment mapping:
Segment Sections...
00 .vector_table .version .text .rodata .ARM.exidx
01 .preinit_array .init_array .fini_array
02 .preinit_array .init_array .fini_array
03
04 .rodata .ARM.exidx
Further questions:
How is GCC able to remove all the RAM sections despite them
previously not having a NOLOAD directive in the linker script?
Running size on Clang's ELF counts the minimum stack size I define in the linker script to the .data section whereas on GCC's ELF it doesn't. How is that? My linker script contains a section which looks like this
._user_heap_stack (NOLOAD) :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
but to my knowledge this should only "check" that there is at least
enough RAM left to cover my defined minimum heap and stack size. This
section doesn't actually contain anything so how can it be counted to
.data?
I know that I could remove unwanted sections with objcopy when actually creating the binaries, but I'd really like to understand those subtle differences between GCC and Clang.
/edit
I just noticed that my ._user_heap_stack section has different types depending on the compiler (NOBITS vs PROGBITS). Guess that explains why it's counted to .data...
/edit
Now a (potential) bug over # LLVM
https://bugs.llvm.org/show_bug.cgi?id=46299
/edit
And closed as of lld 10.0.1
https://bugs.llvm.org/show_bug.cgi?id=46225

Additional data present in flash after last loaded section of elf

I have a STM32 project which involves a bootloader. The bootloader CRCs the entire application region of flash and then compares this value against a firmware header stored just after the application image region in flash.
I wrote a python script which runs after the binary is built. The script takes the elf file resulting from the build, and loads each section into a "virtual flash" image, which represents what should be exactly what is present on the mcu after the elf would be normally loaded. The array starts out being the size of the application region, with initial values of 0xff for every byte, just as flash would be after a full erase. Then, the script takes each section from the elf and overwrites the section of the virtual flash images where that section should reside.
Finally, the script CRCs the application region and injects the resulting value into the original elf.
This all works fine, but I am seeing additional data in the actual flash contents of the mcu that I cannot determine the origin of. The flash is erased fully before programming the elf so this data is coming from the elf loaded onto the device.
I'm guessing that what is going on here is that there are sections in the elf that my script is ignoring but that are still being written to flash when flashed using conventional means.
The following is the result of a readelf on my application image:
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .isr_vector PROGBITS 08020000 010000 0001f8 00 WA 0 0 4
[ 2] .firmware_header_ PROGBITS 080201f8 0101f8 000004 00 WA 0 0 4
[ 3] .text PROGBITS 08020200 010200 01e11c 00 AX 0 0 64
[ 4] .ARM.extab PROGBITS 0803e31c 033a68 000000 00 W 0 0 1
[ 5] .exidx ARM_EXIDX 0803e31c 02e31c 000008 00 AL 3 0 4
[ 6] .ARM.attributes ARM_ATTRIBUTES 0803e324 033a68 000030 00 0 0 1
[ 7] .init_array INIT_ARRAY 0803e324 02e324 000008 04 WA 0 0 4
[ 8] .fini_array FINI_ARRAY 0803e32c 02e32c 000004 04 WA 0 0 4
[ 9] .firmware_header PROGBITS 0803e330 02e330 000008 00 WA 0 0 4
[10] .data PROGBITS 20000000 030000 0009c8 00 WA 0 0 8
[11] .RxDecripSection PROGBITS 200009c8 0309c8 000080 00 WA 0 0 4
[12] .RxarraySection PROGBITS 20000a48 030a48 0017d0 00 WA 0 0 4
[13] .TxDescripSection PROGBITS 20002218 032218 000080 00 WA 0 0 4
[14] .TxarraySection PROGBITS 20002298 032298 0017d0 00 WA 0 0 4
[15] .bss NOBITS 20003a68 033a68 045bc0 00 WA 0 0 8
[16] .heap PROGBITS 20049628 033a98 000000 00 W 0 0 1
[17] .reserved_for_sta PROGBITS 20049628 033a98 000000 00 W 0 0 1
[18] .battery_backed_s NOBITS 40024000 034000 00000c 00 WA 0 0 4
[19] .comment PROGBITS 00000000 033a98 000075 01 MS 0 0 1
[20] .debug_frame PROGBITS 00000000 033b10 001404 00 0 0 4
[21] .stab PROGBITS 00000000 034f14 000084 0c 22 0 4
[22] .stabstr STRTAB 00000000 034f98 000117 00 0 0 1
[23] .symtab SYMTAB 00000000 0350b0 009010 10 24 1646 4
[24] .strtab STRTAB 00000000 03e0c0 003dc8 00 0 0 1
[25] .shstrtab STRTAB 00000000 041e88 000132 00 0 0 1
I am loading the following sections into my virtual flash image: .isr_vector, .firmware_header_vector, .text, .exidx, .ARM.attributes, .init_array, .fini_array
I do notice that some sections do have addresses of 0. Are some of these perhaps simply appended to flash?
The additional sections are most probably initial data for DATA segments. The startup code of most systems copies the contents into the RAM space allocated for those segments. This way static variables initialized with non-zero values are set up.
For example static int x = 23; should give you a segment with "23" in it. The address of this "23" in flash is not the address of x in RAM.

How to genernate position-dependent code for executable file when linking with shared library in gcc?

I'm learning ELF.I want to find the difference of elf format between position-dependent executable file and position-independent executable file when linking shared library.
But I can't genernate position-dependent code for executable file when linking with shared library.
/*Lib.c*/
static int a;
extern int b;
int c=1;
extern void exit();
void set_value()
{
a=1;
b=1;
c=1;
}
void run()
{
set_value();
exit();
}
Fist,use gcc to genrnate a shared dynamic library:
gcc -m32 -nostdlib -o Lib.so Lib.c
Note that I don't use -fpic to generate position-independent code for Lib.so.
Now,I have another file main.c which need to link with Lib.so:
/*main.c*/
extern void run();
int b=2;
void nomain()
{
run();
}
void exit()
{
asm("int $0x80 \n\t"
::"a"(1),"b"(42));
}
use following command to link main.c with Lib.so:
gcc -m32 -e nomain -nostartfiles -fno-builtin -o a.out main.c ./Lib.so
Howerve,gcc will compile main.c to position-independent code defaultly when link with shared library even this library don't use pic.
I wonder whether gcc have some option to genernate position-dependent for executable file?
I post the section information for Lib.so and a.out.We can see there are '.plt' and '.got.plt' section in a.out which mean a.out use PIC.
/*Section for Lib.so*/
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .gnu.hash GNU_HASH 000000b4 0000b4 00003c 04 A 2 0 4
[ 2] .dynsym DYNSYM 000000f0 0000f0 000090 10 A 3 1 4
[ 3] .dynstr STRTAB 00000180 000180 000030 00 A 0 0 1
[ 4] .rel.dyn REL 000001b0 0001b0 000028 08 A 2 0 4
[ 5] .text PROGBITS 000001d8 0001d8 000033 00 AX 0 0 4
[ 6] .dynamic DYNAMIC 0000120c 00020c 000078 08 WA 3 0 4
[ 7] .got.plt PROGBITS 00001284 000284 00000c 04 WA 0 0 4
[ 8] .data PROGBITS 00001290 000290 000004 00 WA 0 0 4
[ 9] .bss NOBITS 00001294 000294 000004 00 WA 0 0 4
[10] .comment PROGBITS 00000000 000294 00002e 00 0 0 1
[11] .shstrtab STRTAB 00000000 0002c2 00006a 00 0 0 1
[12] .symtab SYMTAB 00000000 00055c 000170 10 13 15 4
[13] .strtab STRTAB 00000000 0006cc 000057 00 0 0 1
/*Section for a.out*/
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 080480f4 0000f4 000013 00 A 0 0 1
[ 2] .gnu.hash GNU_HASH 08048108 000108 000034 04 A 3 0 4
[ 3] .dynsym DYNSYM 0804813c 00013c 000070 10 A 4 1 4
[ 4] .dynstr STRTAB 080481ac 0001ac 000037 00 A 0 0 1
[ 5] .rel.plt REL 080481e4 0001e4 000008 08 A 3 6 4
[ 6] .plt PROGBITS 080481ec 0001ec 000020 04 AX 0 0 4
[ 7] .text PROGBITS 0804820c 00020c 000020 00 AX 0 0 4
[ 8] .dynamic DYNAMIC 0804922c 00022c 000090 08 WA 4 0 4
[ 9] .got.plt PROGBITS 080492bc 0002bc 000010 04 WA 0 0 4
[10] .data PROGBITS 080492cc 0002cc 000004 00 WA 0 0 4
[11] .comment PROGBITS 00000000 0002d0 00002e 00 0 0 1
[12] .shstrtab STRTAB 00000000 0002fe 00006d 00 0 0 1
[13] .symtab SYMTAB 00000000 0005c4 000160 10 14 15 4
[14] .strtab STRTAB 00000000 000724 000051 00 0 0 1
You should compile your Lib.so with gcc -Wall -Wextra -m32 -shared -Wl,-soname,Lib.so -o Lib.so Lib.c.
What you did here is just to generate a normal program without relocation information.
Look at this tutorial to know more about dynamic libraries.
Note: Also, don't forget to set your LD_LIBRARY_PATH environment variable in order to point to Lib.so.

Resources