While attempting to build FreeBSD head with clang and lld 9.0.0, I ran into an error message from our elftoolchain-based objcopy, when stripping a boot loader related binary which was linked with lld: objcopy: elf_update() failed: Layout constraint violation The problem turns out to be the alignment of the .rodata section: $ readelf -lSW /usr/obj/share/dim/src/freebsd/clang900-import/amd64.amd64/stand/i386/gptboot/gptboot.out There are 19 section headers, starting at offset 0x2e454: 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 000094 00a504 00 AX 0 0 4 [ 2] .rodata PROGBITS 0000a508 00a59c 0038fb 00 AMS 0 0 8 ... Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000094 0x00000000 0x00000000 0x0df3c 0x0df3c RWE 0x8 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0 E.g., .rodata starts at offset 0xa59c, while its alignment is supposed to be 8 bytes. Similarly, the LOAD segment has an offset of 0x94, while its alignment is 8 bytes. This problem started occurring after https://reviews.llvm.org/rLLD360593 ("[ELF] Full support for -n (--nmagic) and -N (--omagic) via common page"). Before this change, the -N option got largely ignored, which is why we never saw this issue before. Minimal test case: $ cat align-test.s .text .globl _start _start: xor %eax,%eax retl .rodata .align 8 .quad 42 $ cc -m32 -c align-test.s $ readelf -S align-test.o There are 5 section headers, starting at offset 0x88: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .strtab STRTAB 00000000 000060 000026 00 0 0 1 [ 2] .text PROGBITS 00000000 000034 000003 00 AX 0 0 4 [ 3] .rodata PROGBITS 00000000 000038 000008 00 A 0 0 8 [ 4] .symtab SYMTAB 00000000 000040 000020 10 1 1 4 ################################################################ # with ld.lld r360592, everything is page-aligned, even while -N is used: $ ~/llvm/trunk-r360592/bin/ld.lld -m elf_i386_fbsd -N -Ttext 0x0 -o align-test-r360592.out align-test.o $ readelf -lS align-test-r360592.out Elf file type is EXEC (Executable file) Entry point 0x0 There are 2 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0x00000000 0x00000000 0x01000 0x01000 RWE 0x1000 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0 Section to Segment mapping: Segment Sections... 00 .text .rodata 01 There are 7 section headers, starting at offset 0x20a4: 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 001000 000003 00 AX 0 0 4 [ 2] .rodata PROGBITS 00000008 001008 000008 00 A 0 0 8 [ 3] .comment PROGBITS 00000000 002000 000047 01 MS 0 0 1 [ 4] .symtab SYMTAB 00000000 002048 000020 10 6 1 4 [ 5] .shstrtab STRTAB 00000000 002068 000032 00 0 0 1 [ 6] .strtab STRTAB 00000000 00209a 000008 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) ################################################################ # with ld.lld r360593, -N does much more, but messes up the offsets: $ ~/llvm/trunk-r360593/bin/ld.lld -m elf_i386_fbsd -N -Ttext 0x0 -o align-test-r360593.out align-test.o $ readelf -lS align-test-r360593.out Elf file type is EXEC (Executable file) Entry point 0x0 There are 2 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000094 0x00000000 0x00000000 0x00010 0x00010 RWE 0x8 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0 Section to Segment mapping: Segment Sections... 00 .text .rodata 01 There are 7 section headers, starting at offset 0x148: 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 000094 000003 00 AX 0 0 4 [ 2] .rodata PROGBITS 00000008 00009c 000008 00 A 0 0 8 [ 3] .comment PROGBITS 00000000 0000a4 000047 01 MS 0 0 1 [ 4] .symtab SYMTAB 00000000 0000ec 000020 10 6 1 4 [ 5] .shstrtab STRTAB 00000000 00010c 000032 00 0 0 1 [ 6] .strtab STRTAB 00000000 00013e 000008 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
Not sure if this should block 9.0, it's probably overkill, and we're already at rc3 ... :-/
I confirmed the issue and trying to fix it. It looks like a regression of the -N option, and it can cause a real issue due to unaligned accesses. If a fix is executed only when -N is given and is small, we may want to cherry-pick it to the LLVM9 tree.
As I remember it -n and -N disable page alignment by setting the max and common page size to 1. At a first guess there is some place in the code where there is an alignment done exclusively on pagesize and not max(os->alignment, pagesize) that is triggering a problem.
ruiu fixed it in D67152/r371013. dim, you may add it to the 9.0.1 wish list (once there is a tracking bug for 9.0.1)?
(In reply to Fangrui Song from comment #4) > ruiu fixed it in D67152/r371013. > > dim, you may add it to the 9.0.1 wish list (once there is a tracking bug for > 9.0.1)? Thanks, I will do that. I have already pulled it into FreeBSD's import branch for 9.0.0, here: https://svnweb.freebsd.org/changeset/base/351879 Note that this also needs http://reviews.llvm.org/rLLD369828 as a prerequisite.