FreeBSD's amd64 (x86_64) kernel linker script uses MAXPAGESIZE to set the physical and virtual addresses for the kernel. See https://svnweb.freebsd.org/base/head/sys/conf/ldscript.amd64?annotate=303442#l9 After r282560 (https://reviews.llvm.org/rL282560) lld sets MAXPAGESIZE to 0x1000 not 0x200000. The FreeBSD kernel then occupies the physical memory under 640K and the kernel panics on boot when a device that requires a low memory allocation fails.
From the description it looks like the linker script should just say kernphys = 0x200000; or maybe kernphys = 0xa0000 Since it is not really trying to reason about the page size. It is trying to make sure there is some free memory before the kernel.
It's actually trying to do both - a driver panics if there is no low (below 640K) memory available which happens as a side effect of kernphys = 0x1000, but the reason it's currently MAXPAGESIZE is so that the kernel physical address is large-page aligned.
Related FreeBSD bug for the driver panic: https://bugs.freebsd.org/214718
Some discussion in https://reviews.llvm.org/D24987 and in the review thread on llvm-commits (some of which seems to be missing from the archives) Linking a "hello world" with one int in .data using default ld 2.17.50 settings on FreeBSD gives me (omitting PHDR, INTERP, DYNAMIC, etc. sections): Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x000000000000086c 0x000000000000086c R E 200000 LOAD 0x0000000000000870 0x0000000000600870 0x0000000000600870 0x00000000000001f0 0x00000000000001f8 RW 200000 With ld.bfd from the binutils package, 2.25.1: LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x000000000000089c 0x000000000000089c R E 200000 LOAD 0x00000000000008a0 0x00000000006008a0 0x00000000006008a0 0x00000000000001f0 0x00000000000001f8 RW 200000 With ld.gold 2.25.1: LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000008b0 0x00000000000008b0 R E 1000 LOAD 0x00000000000008b0 0x00000000004018b0 0x00000000004018b0 0x00000000000001f0 0x00000000000001f8 RW 1000 With ld.lld HEAD: LOAD 0x0000000000000000 0x0000000000010000 0x0000000000010000 0x0000000000000564 0x0000000000000564 R 1000 LOAD 0x0000000000001000 0x0000000000011000 0x0000000000011000 0x0000000000000340 0x0000000000000340 R E 1000 LOAD 0x0000000000002000 0x0000000000012000 0x0000000000012000 0x0000000000001058 0x0000000000001060 RW 1000
(In reply to comment #4) > Some discussion in https://reviews.llvm.org/D24987 and in the review thread > on llvm-commits (some of which seems to be missing from the archives) > > Linking a "hello world" with one int in .data using default ld 2.17.50 > settings on FreeBSD gives me (omitting PHDR, INTERP, DYNAMIC, etc. sections): > > Type Offset VirtAddr PhysAddr > FileSiz MemSiz Flags Align > LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 > 0x000000000000086c 0x000000000000086c R E 200000 > LOAD 0x0000000000000870 0x0000000000600870 0x0000000000600870 > 0x00000000000001f0 0x00000000000001f8 RW 200000 > > With ld.bfd from the binutils package, 2.25.1: > > LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 > 0x000000000000089c 0x000000000000089c R E 200000 > LOAD 0x00000000000008a0 0x00000000006008a0 0x00000000006008a0 > 0x00000000000001f0 0x00000000000001f8 RW 200000 So both use a 2MB page, merge read and executable sections and overlap PT_LOAD. > With ld.gold 2.25.1: > > LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 > 0x00000000000008b0 0x00000000000008b0 R E 1000 > LOAD 0x00000000000008b0 0x00000000004018b0 0x00000000004018b0 > 0x00000000000001f0 0x00000000000001f8 RW 1000 Same as bfd, but with a 4k page. You can get the 3 LOADs with --rosegment. > With ld.lld HEAD: > > LOAD 0x0000000000000000 0x0000000000010000 0x0000000000010000 > 0x0000000000000564 0x0000000000000564 R 1000 > LOAD 0x0000000000001000 0x0000000000011000 0x0000000000011000 > 0x0000000000000340 0x0000000000000340 R E 1000 > LOAD 0x0000000000002000 0x0000000000012000 0x0000000000012000 > 0x0000000000001058 0x0000000000001060 RW 1000 4k pages, --rosegment, don't overlap segments.
(In reply to comment #5) > > So both [ld.bfd 2.17.50 and ld.bfd 2.25.1] use a 2MB page, merge read > and executable sections and overlap PT_LOAD. Interesting: the PT_LOAD overlaps on disk, but the run-time page permissions are applied on a 4K page boundary. PID START END PRT RES PRES REF SHD FL TP PATH 22056 0x400000 0x401000 r-x 1 0 1 0 C--- vn /home/emaste/a.out 22056 0x600000 0x601000 rw- 1 1 1 0 ---- df > > With ld.gold 2.25.1: > > Same as bfd, but with a 4k page. The net result ends up the same though, some overlapping content and 4K run-time permissions. 22108 0x400000 0x401000 r-x 1 0 1 0 C--- vn /home/emaste/a.out 22108 0x401000 0x402000 rw- 1 1 1 0 ---- df > You can get the 3 LOADs with --rosegment. Do you know if ld.gold defaults to enabling this on Linux, out of curiosity?
Proposed FreeBSD change is in https://reviews.freebsd.org/D8610
(In reply to comment #6) > (In reply to comment #5) > > > > So both [ld.bfd 2.17.50 and ld.bfd 2.25.1] use a 2MB page, merge read > > and executable sections and overlap PT_LOAD. > > Interesting: the PT_LOAD overlaps on disk, but the run-time page permissions > are applied on a 4K page boundary. > > PID START END PRT RES PRES REF SHD FL TP > PATH > 22056 0x400000 0x401000 r-x 1 0 1 0 C--- vn > /home/emaste/a.out > 22056 0x600000 0x601000 rw- 1 1 1 0 ---- df Looks 2MiB to me, no? > > You can get the 3 LOADs with --rosegment. > > Do you know if ld.gold defaults to enabling this on Linux, out of curiosity? It does not.
(In reply to comment #8) > > PID START END PRT RES PRES REF SHD FL TP > > PATH > > 22056 0x400000 0x401000 r-x 1 0 1 0 C--- vn > > /home/emaste/a.out > > 22056 0x600000 0x601000 rw- 1 1 1 0 ---- df > > Looks 2MiB to me, no? I mean they are aligned to 2MiB from ld.bfd's MAXPAGESIZE, but are 4KiB runtime mappings (END-START), and they have the same content.