LLD is not necessarily wrong here and what ld.bfd is doing is arguably a bug, but I'm submitting this PR for tracking one of the few outstanding issues linking FreeBSD/amd64 with LLD while looking for a solution. We recently migrated to using a linker script instead of the seemingly obsolete -N command line flag for FreeBSD's boot loader components: https://svnweb.freebsd.org/base?view=revision&revision=305353 The linker script is straightforward: --- /* $FreeBSD$ */ /* Merge text, data and bss together almost no padding */ OUTPUT_FORMAT("elf32-i386-freebsd") OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { . = 0x08048000 + SIZEOF_HEADERS; .text : { *(.text) } =0x90909090 /* Pad with nops, if needed */ .data : { *(.data) } PROVIDE(_edata = .); .bss : { *(.bss) } PROVIDE(_end = .); } --- From this GNU ld produces an object with all sections packed into a single RWE segment: % readelf -l boot2.out Elf file type is EXEC (Executable file) Entry point 0x2000 There are 2 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000080 0x00002000 0x00002000 0x01456 0x027f8 RWE 0x10 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 Section to Segment mapping: Segment Sections... 00 .text .rodata .data .bss 01 while LLD produces an object with separate segments for sections with different permissions.
Why is having multiple PT_LOADs a problem?
If you want to merge it all in one output section, I think you can do .all : { *(.text) *(.data) *(.bss) }
> Why is having multiple PT_LOADs a problem? Sorry, multiple PT_LOADs is not a problem per se, but the resulting binary produced by lld is too large.
> .all : { *(.text) *(.data) *(.bss) } With that I end up failing because there's no section for relocations: mbr.o: In function `start': (.text+0xd): relocation truncated to fit: R_386_16 against `.text'
(In reply to comment #4) > > .all : { *(.text) *(.data) *(.bss) } > > With that I end up failing because there's no section for relocations: > > mbr.o: In function `start': > (.text+0xd): relocation truncated to fit: R_386_16 against `.text' Can you check if this is still a problem and upload a cpio if it is?
A little more information: FreeBSD switched to a linker script for these boot loaders in r305353 (https://svnweb.freebsd.org/base?view=revision&revision=305353, https://reviews.freebsd.org/D7409) However, it broke one of the loaders when using ld.bfd (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=213491) and was reverted in r307954 (https://svnweb.freebsd.org/base?view=revision&revision=307954) Most of the boot components worked with the linker script version though, and I expect we'll fix the breakage and restore the use of the linker script. I will try re-applying r305353 and generating a reproduction cpio at some point, but I believe the EFI loaders are more important to fix first and am helping George investigate those first.
(In reply to comment #6) > A little more information: > > FreeBSD switched to a linker script for these boot loaders in r305353 > (https://svnweb.freebsd.org/base?view=revision&revision=305353, > https://reviews.freebsd.org/D7409) > > However, it broke one of the loaders when using ld.bfd > (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=213491) > and was reverted in r307954 > (https://svnweb.freebsd.org/base?view=revision&revision=307954) > > Most of the boot components worked with the linker script version though, > and I expect we'll fix the breakage and restore the use of the linker script. > > I will try re-applying r305353 and generating a reproduction cpio at some > point, but I believe the EFI loaders are more important to fix first and am > helping George investigate those first. Note that given that we already support putting ro and rx together because of linker scripts, supporting the original feature might not be a big problem.
lld doesn't create one single RWX PT_LOAD now. Closing because the issue has been fixed for a while. # I test on a Linux machine, but the FreeBSD case is similar. % clang -fuse-ld=lld -m32 a.c a.x -o a # 5008 bytes Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x00140 0x00140 R 0x4 INTERP 0x000174 0x08048174 0x08048174 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x00730 0x00730 R E 0x1000 LOAD 0x000730 0x08048730 0x08048730 0x000d8 0x000d8 RW 0x1000 LOAD 0x000808 0x08048808 0x08048808 0x00020 0x00021 RW 0x1000 DYNAMIC 0x000738 0x08048738 0x08048738 0x000c8 0x000c8 RW 0x4 GNU_RELRO 0x000730 0x08048730 0x08048730 0x000d8 0x01000 R 0x1 GNU_EH_FRAME 0x000378 0x08048378 0x08048378 0x00044 0x00044 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0 NOTE 0x000188 0x08048188 0x08048188 0x00020 0x00020 R 0x4 After D64903 and D64906 are merged, the non-linker script case will look similar to this layout. % clang -fuse-ld=bfd -m32 a.c a.x -o a.bfd # 7148 bytes % readelf -l a.bfd ... Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R 0x4 INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x005dc 0x005dc R E 0x1000 LOAD 0x000f04 0x08049f04 0x08049f04 0x00118 0x0011c RW 0x1000 DYNAMIC 0x000f0c 0x08049f0c 0x08049f0c 0x000f0 0x000f0 RW 0x4 NOTE 0x000168 0x08048168 0x08048168 0x00020 0x00020 R 0x4 GNU_EH_FRAME 0x0004c8 0x080484c8 0x080484c8 0x00034 0x00034 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10 GNU_RELRO 0x000f04 0x08049f04 0x08049f04 0x000fc 0x000fc R 0x1 > Note that given that we already support putting ro and rx together because of linker scripts, supporting the original feature might not be a big problem. After https://reviews.llvm.org/rLLD281978, we place R and RX sections in the RX PT_LOAD (`singleRoRx = true;` in ScriptParser.cpp). I actually want to flip this, to improve consistency with the non-linker script case, and to fix issues like https://bugs.llvm.org/show_bug.cgi?id=38784 People who want separate R PT_LOAD and RX PT_LOAD in linker script cases can enable --no-rosegment.