Page MenuHomeFreeBSD

Link stand/i386 components using a linker script
ClosedPublic

Authored by dim on Mar 3 2020, 7:27 PM.

Details

Summary

LLD 10.0.0 changed the behavior of the -Ttext option, so that using
-Ttext=0x0 now causes linking of the loaders to fail with:

ld: error: output file too large: 18446744073707016908 bytes

I reported this in https://bugs.llvm.org/show_bug.cgi?id=44715, and
initially reverted the upstream change in rS357259 to work around it.

However, after some discussion with Fangrui Song in the upstream ticket,
I think we can classify this as an unfortunate interaction between using
-Ttext=0 in combination with --no-rosegment. (We added the latter
in rS332090, because btxld does not correctly handle input with more
than 2 PT_LOAD segments.)

Fangrui suggested to use a linker script instead, and Warner was already
attempting this in rS305353, but had to revert it due to "crypto-using
boot problems" (not sure what those were :).

This review updates the stand/i386/boot.ldscript to handle more
sections, inserts some symbols like _edata and such that we use in
libsa, and also discards any .interp section.

It uses ORG which is defined on the linker command line using
--defsym ORG=value to set the start of all the sections.

Test Plan
  • Build it with clang and lld 9.0.1 (works), install it, and attempt booting (have to try this on a clean VM)
  • Build it with clang and lld 10.0.0, install it, and attempt booting (works on my clang1000-import VMs)
  • Build it with gcc 9.2 and ld.bfd 2.33, install it, and attempt booting (also works on my VMs)

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

Assuming this all tests good, and I think it will, go for it. Have you tested binutils too?

This revision is now accepted and ready to land.Mar 4 2020, 3:15 AM
In D23952#526438, @imp wrote:

Assuming this all tests good, and I think it will, go for it. Have you tested binutils too?

I have tested the combination of ports gcc and binutils; /usr/local/bin/gcc prefers to invoke /usr/local/bin/ld. I should probably also try clang with -fuse-ld=bfd, to see how that works.

In D23952#526455, @dim wrote:
In D23952#526438, @imp wrote:

Assuming this all tests good, and I think it will, go for it. Have you tested binutils too?

I have tested the combination of ports gcc and binutils; /usr/local/bin/gcc prefers to invoke /usr/local/bin/ld. I should probably also try clang with -fuse-ld=bfd, to see how that works.

It would be best, but it is an odd combo...

I really hope some administrator can change my username to something more sensible.

stand/i386/boot.ldscript
6 ↗(On Diff #69139)

For boot loaders, it may be good to have PHDRS to suppress automatically generated program headers.

16 ↗(On Diff #69139)

Is this needed?

stand/i386/boot.ldscript
6 ↗(On Diff #69139)

Most of the boot loaders get post-processed, either by specifying --oformat=binary, or using objcopy or btxld. But what kind of PHDRS declaration would make sense here?

16 ↗(On Diff #69139)

Yes, otherwise some images get a bogus section appended, with the dynamic linker string in it. This is something that changed between lld 9.0 and 10.0, but I have no idea where. For example, /boot/mbr would then look like this:

$ hexdump -C /boot/mbr
00000000  fc 31 c0 8e c0 8e d8 8e  d0 bc 00 7c be 1a 7c bf  |.1.........|..|.|
00000010  1a 06 b9 e6 01 f3 a4 e9  00 8a 31 f6 bb be 07 b1  |..........1.....|
00000020  04 38 2f 74 08 7f 78 85  f6 75 74 89 de 80 c3 10  |.8/t..x..ut.....|
00000030  e2 ef 85 f6 75 02 cd 18  80 fa 80 72 0b 8a 36 75  |....u......r..6u|
00000040  04 80 c6 80 38 f2 72 02  8a 14 89 e7 8a 74 01 8b  |....8.r......t..|
00000050  4c 02 bb 00 7c 67 f6 05  bd 07 00 00 80 74 2d 51  |L...|g.......t-Q|
00000060  53 bb aa 55 b4 41 cd 13  72 20 81 fb 55 aa 75 1a  |S..U.A..r ..U.u.|
00000070  f6 c1 01 74 15 5b 66 6a  00 66 ff 74 08 06 53 6a  |...t.[fj.f.t..Sj|
00000080  01 6a 10 89 e6 b8 00 42  eb 05 5b 59 b8 01 02 cd  |.j.....B..[Y....|
00000090  13 89 fc 72 0f 81 bf fe  01 55 aa 75 0c ff e3 be  |...r.....U.u....|
000000a0  bc 06 eb 11 be d4 06 eb  0c be f3 06 eb 07 bb 07  |................|
000000b0  00 b4 0e cd 10 ac 84 c0  75 f4 eb fe 49 6e 76 61  |........u...Inva|
000000c0  6c 69 64 20 70 61 72 74  69 74 69 6f 6e 20 74 61  |lid partition ta|
000000d0  62 6c 65 00 45 72 72 6f  72 20 6c 6f 61 64 69 6e  |ble.Error loadin|
000000e0  67 20 6f 70 65 72 61 74  69 6e 67 20 73 79 73 74  |g operating syst|
000000f0  65 6d 00 4d 69 73 73 69  6e 67 20 6f 70 65 72 61  |em.Missing opera|
00000100  74 69 6e 67 20 73 79 73  74 65 6d 00 90 90 90 90  |ting system.....|
00000110  90 90 90 90 90 90 90 90  90 90 90 90 90 90 90 90  |................|
*
000001b0  90 90 90 90 90 90 90 90  90 90 90 90 90 80 00 00  |................|
000001c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  2f 6c 69 62 65 78 65 63  2f 6c 64 2d 65 6c 66 2e  |/libexec/ld-elf.|
00000210  73 6f 2e 31 00 00 00 00                           |so.1....|
00000218

The DISCARD makes the part with /libexec/ld-elf.so.1 go away, and reduces the size again to 512 bytes.

stand/i386/boot.ldscript
6 ↗(On Diff #69139)

We should investigate that, perhaps after we get these changes in. We may be able to do it when we're doing objcopy today, though replacing btxld usage may be harder.

In general, the convoluted mess we have to day is the result of co-evolving with gcc, binutils, clang and now lld. There's nothing special about any of it, other than it generates code that works. If there's a better way to get there, I'm quite open to investigating it since what we have today is fragile and overly copied between different loaders.

This revision was automatically updated to reflect the committed changes.