OSDev.org https://forum.osdev.org/ |
|
[solved] clang not aligning my elf program headers https://forum.osdev.org/viewtopic.php?f=1&t=48082 |
Page 1 of 1 |
Author: | kzinti [ Sun Aug 01, 2021 10:21 pm ] |
Post subject: | [solved] clang not aligning my elf program headers |
So I have some linker script that I use to link my kernel. I specify 3 program headers and align them on page boundaries (4K). This works well with GCC where I link using gcc: Code: 21:15:34-kzinti@droneship:~/dev/rainbow-os (master)$ readelf -l build/arch/x86_64/kernel/kernel Elf file type is EXEC (Executable file) Entry point 0xffffffff8000b708 There are 3 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff80000000 0xffffffff80000000 0x000000000000f35c 0x000000000000f35c R E 0x1000 LOAD 0x0000000000011000 0xffffffff80010000 0xffffffff80010000 0x00000000000053fc 0x00000000000053fc R 0x1000 LOAD 0x0000000000017000 0xffffffff80016000 0xffffffff80016000 0x0000000000002013 0x000000000002d002 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .text 01 .rodata .eh_frame 02 .data .init_array .fini_array .vdso .bss Now I have decided to dump gcc and adopt clang. Here is what I get: Code: 21:17:53-kzinti@droneship:~/dev/rainbow-os-2/build (master)$ readelf -l kernel/src/kernel Elf file type is EXEC (Executable file) Entry point 0xffffffff80000000 There are 3 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff80000000 0xffffffff80000000 0x000000000000000e 0x000000000000000e R E 0x1000 LOAD 0x000000000000100e 0xffffffff8000000e 0xffffffff8000000e 0x000000000000007e 0x000000000000007e R 0x1000 LOAD 0x0000000000001090 0xffffffff80000090 0xffffffff80000090 0x00000000000000e0 0x00000000000000e0 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .text 01 .interp .note.gnu.build-id .dynsym .dynstr .gnu.hash 02 .dynamic Notice that: 1) The alignment of each program header is "0x1000" as expected. 2) The offset (and virtual address) of the last two program headers is (are) NOT aligned to 0x1000. This I did not expect. 3) Not the same code is compiled in both cases, but that doesn't explain #2 Perhaps my link script needs fixing but I am not sure what. I have been unsuccessful at the googles. Here is my link script (same used in both cases): https://github.com/kiznit/rainbow-os/bl ... kernel.lds |
Author: | Korona [ Mon Aug 02, 2021 1:53 am ] |
Post subject: | Re: clang not aligning my elf program headers |
Both linkers align correctly: the alignment requirements of the ELF standard demand that p_vaddr % p_align == p_offset % p_align, but not that this expression equals zero. p_align is basically the page size (which can be modified by some command line arguments to ld/lld). This requirements is designed such that it is possible to map the segments from the file into memory (because addresses and offsets match modulo the page size), while still keeping the file size minimal (there is no need to insert padding into the file). If you want the segments to be 4k-aligned, you have to insert padding manually in your linker script (but that will add a bit of overhead in terms of disk usage). If you want the segments to start on different pages, it's enough to ensure that the vaddrs are at least 0x1000 apart (e.g., by doing . += 0x1000 in the linker script). This should be enough to properly map the segments at runtime and it's preferable to manual padding. |
Author: | kzinti [ Mon Aug 02, 2021 8:44 am ] |
Post subject: | Re: clang not aligning my elf program headers |
Korona wrote: If you want the segments to start on different pages, it's enough to ensure that the vaddrs are at least 0x1000 apart (e.g., by doing . += 0x1000 in the linker script). This should be enough to properly map the segments at runtime and it's preferable to manual padding. Can you clarify how this works? I've tried adding ". += 0x1000" in a few places and it doesn't appear to do anything (some results as before). Also adding 0x1000 to the vaddr doesn't appear to be what i need, I want the vaddr to be aligned to the next page boundary, not moved 0x1000 bytes ahead. Seems to me that the issue is that gcc will link program headers on page boundaries by default and clang doesn't. Ultimately I want to be different program headers to be aligned to pages so that i can map them with different memory protections. I also need to be able to map the VDSO page(s) in user space: this also needs to be page-aligned and padded to not leak kernel data/code into user space. Code: SECTIONS { . = 0xFFFFFFFF80000000; .text ALIGN(4K) : { *(.text*) } :phdr_text . += 0x1000; .rodata ALIGN(4K) : { *(.rodata*) } :phdr_rodata . += 0x1000; .data ALIGN(4K) : { *(.data*) } :phdr_data The following seems to almost work: Code: SECTIONS { . = 0xFFFFFFFF80000000; .text ALIGN(4K) : { *(.text*) } :phdr_text .rodata ALIGN(4K) : { . = (. & ~0xFFF) + 0x1000; *(.rodata*) } :phdr_rodata .data ALIGN(4K) : { . = (. & ~0xFFF) + 0x1000; *(.data*) } :phdr_data Code: 08:11:36-kzinti@droneship:~/dev/rainbow-os-2/build (master)$ readelf -l kernel/src/kernel
Elf file type is EXEC (Executable file) Entry point 0xffffffff80000000 There are 3 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff80000000 0xffffffff80000000 0x000000000000000e 0x000000000000000e R E 0x1000 LOAD 0x0000000000002000 0xffffffff80001000 0xffffffff80001000 0x000000000000107c 0x000000000000107c R 0x1000 LOAD 0x0000000000004000 0xffffffff80003000 0xffffffff80003000 0x00000000000010e0 0x00000000000010e0 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .text 01 .rodata .interp .note.gnu.build-id .dynsym .dynstr .gnu.hash 02 .data .dynamic |
Author: | kzinti [ Mon Aug 02, 2021 9:31 am ] |
Post subject: | Re: clang not aligning my elf program headers |
Accoding to all the info I can find, putting ALIGN() on a section should do what i want it to do (but doesn't work with clang). See "ALIGN" in the manual here: https://ftp.gnu.org/old-gnu/Manuals/ld- ... /ld_3.html Quote: As an example, to align the output .data section to the next 0x2000 byte boundary after the preceding section and to set a variable within the section to the next 0x8000 boundary after the input sections:
SECTIONS{ ... .data ALIGN(0x2000): { *(.data) variable = ALIGN(0x8000); } ... } |
Author: | linuxyne [ Mon Aug 02, 2021 9:46 am ] |
Post subject: | Re: clang not aligning my elf program headers |
In your original post where the output from clang compilation is shown, there aren't any rodata or data sections created, but these are the sections in the .lds that govern the alignment. Is the absence of those sections which define the alignment a possible cause for the unaligned segments? |
Author: | kzinti [ Mon Aug 02, 2021 9:50 am ] |
Post subject: | Re: clang not aligning my elf program headers |
linuxyne wrote: In your original post where the output from clang compilation is shown, there aren't any rodata or data sections created, but these are the sections in the .lds that govern the alignment. Is the absence of those sections which define the alignment a possible cause for the unaligned segments? Interestingly enough, my current kernel doesn't have any data / rodata in it (!!!). So maybe it's working properly. Let me add some data and see what happens. |
Author: | kzinti [ Mon Aug 02, 2021 9:56 am ] |
Post subject: | Re: clang not aligning my elf program headers |
I added some data and rodata and it works just fine. Sounds like it was a 12 inch problem. Code: Elf file type is EXEC (Executable file)
Entry point 0xffffffff80000000 There are 3 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000001000 0xffffffff80000000 0xffffffff80000000 0x0000000000000017 0x0000000000000017 R E 0x1000 LOAD 0x0000000000002000 0xffffffff80001000 0xffffffff80001000 0x000000000000008c 0x000000000000008c R 0x1000 LOAD 0x0000000000003000 0xffffffff80002000 0xffffffff80002000 0x0000000000000108 0x0000000000000108 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .text 01 .rodata .interp .note.gnu.build-id .dynsym .dynstr .gnu.hash 02 .data .dynamic |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |