Linking e.g. zfsloader reports (whitespace added for clarity): cc -O2 -pipe -I/usr/home/emaste/src/freebsd-wip/stand/i386/btx/lib -nostdinc -I/usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/libsa32 -I/usr/home/emaste/src/freebsd-wip/stand/libsa -D_STANDALONE -I/usr/home/emaste/src/freebsd-wip/sys -DLOADER_GELI_SUPPORT -I/usr/home/emaste/src/freebsd-wip/stand/geli -DLOADER_DISK_SUPPORT -m32 -mcpu=i386 -ffreestanding -mno-mmx -mno-sse -mno-avx -mno-avx2 -msoft-float -march=i386 -I. -I/usr/home/emaste/src/freebsd-wip/stand/common -I/usr/home/emaste/src/freebsd-wip/stand/ficl -I/usr/home/emaste/src/freebsd-wip/stand/ficl/i386 -I/usr/home/emaste/src/freebsd-wip/stand/common -DBF_DICTSIZE=15000 -DLOADER_UFS_SUPPORT -DLOADER_GZIP_SUPPORT -DLOADER_BZIP2_SUPPORT -DLOADER_NET_SUPPORT -DLOADER_NFS_SUPPORT -DLOADER_TFTP_SUPPORT -DLOADER_GPT_SUPPORT -DLOADER_MBR_SUPPORT -DLOADER_ZFS_SUPPORT -I/usr/home/emaste/src/freebsd-wip/stand/zfs -I/usr/home/emaste/src/freebsd-wip/sys/cddl/boot/zfs -Wall -I/usr/home/emaste/src/freebsd-wip/stand/i386 -DLOADER_PREFER_AMD64 -std=gnu99 -Wsystem-headers -Werror -Wno-pointer-sign -Wno-empty-body -Wno-string-plus-int -Wno-unused-const-variable -Wno-tautological-compare -Wno-unused-value -Wno-parentheses-equality -Wno-unused-function -Wno-enum-conversion -Wno-unused-local-typedef -Wno-address-of-packed-member -Wno-switch -Wno-switch-enum -Wno-knr-promoted-parameter -Wno-parentheses -Qunused-arguments -nostdlib -Wl,-z,norelro -static -Ttext 0x0 -Wl,-z,norelro -o zfsloader.sym /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/i386/btx/lib/crt0.o main.o conf.o vers.o chain.o boot.o commands.o console.o devopen.o interp.o interp_backslash.o interp_parse.o ls.o misc.o module.o load_elf32.o load_elf32_obj.o reloc_elf32.o load_elf64.o load_elf64_obj.o reloc_elf64.o disk.o part.o dev_net.o bcache.o isapnp.o pnp.o interp_forth.o /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/ficl32/libficl.a /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/zfs32/libzfsboot.a /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/i386/libi386/libi386.a /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/geli/libgeliboot.a /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/libsa32/libsa32.a strip -R .comment -R .note -o zfsloader.bin zfsloader.sym btxld -v -f aout -e 0x200000 -o zfsloader -l /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/i386/btx/btxldr/btxldr -b /usr/obj/usr/home/emaste/src/freebsd-wip/amd64.amd64/stand/i386/btx/btx/btx zfsloader.bin btxld: zfsloader.bin: Warning: Ignoring extra elf PT_LOAD segments kernel: ver=1.02 size=690 load=9000 entry=9010 map=16M pgctl=0:59 client: fmt=elf size=6bcd0 text=58834 data=afec bss=0 entry=0 output: fmt=aout size=6f000 text=1000 data=6d000 org=200000 entry=200000 btxld has: case 2: Warn(fname, "Ignoring extra %s PT_LOAD segments", fmtlist[fmt]); i.e., it expects two PT_LOADs with a specific format, and just ignores the third or later ones.
Just curious, why the boot code may need more than two segments. It would be interesting to see readelf or objdump output for zfsloader.bin.
It is because lld collects read-only contents into a separate segment, for example: % readelf -l zfsloader.sym Elf file type is EXEC (Executable file) Entry point 0x0 There are 5 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0x00000000 0x00000000 0x58694 0x58694 R E 0x1000 LOAD 0x05a000 0x00059000 0x00059000 0x0afcc 0x0afcc R 0x1000 LOAD 0x065000 0x00064000 0x00064000 0x07854 0x14c9c RW 0x1000 GNU_RELRO 0x06c000 0x0006b000 0x0006b000 0x00854 0x01000 R 0x1 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0 Section to Segment mapping: Segment Sections... 00 .text .gnu_debuglink .comment .debug_str .debug_loc .debug_abbrev .debug_info .debug_ranges .debug_macinfo .debug_pubnames .debug_pubtypes .debug_frame .debug_line .debug_aranges .symtab .shstrtab .strtab 01 .rodata set_Xcommand_set 02 .data set_Xficl_compile_set .data.rel.ro .got .bss 03 .data.rel.ro .got 04 Linking with -z norelro leaves the three PT_LOADs, just the PT_GNU_RELRO is not emitted. From the output above btxld should coalesce two PT_LOADs, and discarding a PT_LOAD should be an error not a warning.
See https://reviews.freebsd.org/D14956, which stops lld from generating > 2 PT_LOADs. The underlying issue in btxld will still exist. IMO we should upgrade the warning btxld: zfsloader.bin: Warning: Ignoring extra elf PT_LOAD segments to an error to ensure we won't silently ignore segments in the future, and such a change is sufficient to resolve this.
A commit references this bug: Author: emaste Date: Fri Apr 6 02:57:59 UTC 2018 New revision: 332090 URL: https://svnweb.freebsd.org/changeset/base/332090 Log: stand: pass --no-rosegment for i386 bits when linking with lld btxld does not correctly handle input with other than 2 PT_LOAD segments. Passing --no-rosegment lets lld produce output eqivalent to ld.bfd: 2 PT_LOAD segments and no PT_GNU_RELRO. PR: 225775 MFC after: 3 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D14956 Changes: head/stand/i386/Makefile.inc
A commit references this bug: Author: emaste Date: Fri Apr 27 01:21:52 UTC 2018 New revision: 333048 URL: https://svnweb.freebsd.org/changeset/base/333048 Log: MFC r332090: stand: pass --no-rosegment for i386 bits when linking with lld btxld does not correctly handle input with other than 2 PT_LOAD segments. Passing --no-rosegment lets lld produce output eqivalent to ld.bfd: 2 PT_LOAD segments and no PT_GNU_RELRO. PR: 225775 Sponsored by: The FreeBSD Foundation Changes: _U stable/11/ stable/11/stand/i386/Makefile.inc
Fix commited, closing