Work around lld's inability to handle undefined weak symbols on risc-v.

lld on RISC-V is not yet able to handle undefined weak symbols for
non-PIC code in the code model (medany/medium) used by the RISC-V
kernel.

Both GCC and clang emit an auipc / addi pair of instructions to
generate an address relative to the current PC with a 31-bit offset.
Undefined weak symbols need to have an address of 0, but the kernel
runs with PC values much greater than 2^31, so there is no way to
construct a NULL pointer as a PC-relative value.  The bfd linker
rewrites the instruction pair to use lui / addi with values of 0 to
force a NULL pointer address.  (There are similar cases for 'ld'
becoming auipc / ld that bfd rewrites to lui / ld with an address of
0.)

To work around this, compile the kernel with -fPIE when using lld.
This does not make the kernel position-independent, but it does
force the compiler to indirect address lookups through GOT entries
(so auipc / ld against a GOT entry to fetch the address).  This
adds extra memory indirections for global symbols, so should be
disabled once lld is finally fixed.

A few 'la' instructions in locore that depend on PC-relative
addressing to load physical addresses before paging is enabled have to
use auipc / addi and not indirect via GOT entries, so change those to
use 'lla' which always uses auipc / addi for both PIC and non-PIC.

Submitted by:	jrtc27
Sponsored by:	DARPA
Differential Revision:	https://reviews.freebsd.org/D23064
This commit is contained in:
John Baldwin 2020-01-07 23:18:31 +00:00
parent 1c7dd40e58
commit f39b4f8899
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356481
2 changed files with 21 additions and 10 deletions

View File

@ -170,6 +170,17 @@ LDFLAGS+= -z notext -z ifunc-noplt
.endif
.endif
.if ${MACHINE_CPUARCH} == "riscv"
# Hack: Work around undefined weak symbols being out of range when linking with
# LLD (address is a PC-relative calculation, and BFD works around this by
# rewriting the instructions to generate an absolute address of 0); -fPIE
# avoids this since it uses the GOT for all extern symbols, which is overly
# inefficient for us. Drop once undefined weak symbols work with medany.
.if ${LINKER_TYPE} == "lld"
CFLAGS+= -fPIE
.endif
.endif
NORMAL_C= ${CC} -c ${CFLAGS} ${WERROR} ${PROF} ${.IMPSRC}
NORMAL_S= ${CC:N${CCACHE_BIN}} -c ${ASM_CFLAGS} ${WERROR} ${.IMPSRC}
PROFILE_C= ${CC} -c ${CFLAGS} ${WERROR} ${.IMPSRC}

View File

@ -54,7 +54,7 @@
.globl _start
_start:
/* Get the physical address kernel loaded to */
la t0, virt_map
lla t0, virt_map
ld t1, 0(t0)
sub t1, t1, t0
li t2, KERNBASE
@ -66,7 +66,7 @@ _start:
*/
/* Pick a hart to run the boot process. */
la t0, hart_lottery
lla t0, hart_lottery
li t1, 1
amoadd.w t0, t1, 0(t0)
@ -82,8 +82,8 @@ _start:
*/
1:
/* Add L1 entry for kernel */
la s1, pagetable_l1
la s2, pagetable_l2 /* Link to next level PN */
lla s1, pagetable_l1
lla s2, pagetable_l2 /* Link to next level PN */
srli s2, s2, PAGE_SHIFT
li a5, KERNBASE
@ -100,7 +100,7 @@ _start:
sd t6, (t0)
/* Level 2 superpages (512 x 2MiB) */
la s1, pagetable_l2
lla s1, pagetable_l2
srli t4, s9, 21 /* Div physmem base by 2 MiB */
li t2, 512 /* Build 512 entries */
add t3, t4, t2
@ -116,8 +116,8 @@ _start:
bltu t4, t3, 2b
/* Create an L1 page for early devmap */
la s1, pagetable_l1
la s2, pagetable_l2_devmap /* Link to next level PN */
lla s1, pagetable_l1
lla s2, pagetable_l2_devmap /* Link to next level PN */
srli s2, s2, PAGE_SHIFT
li a5, (VM_MAX_KERNEL_ADDRESS - L2_SIZE)
@ -134,7 +134,7 @@ _start:
sd t6, (t0)
/* Create an L2 page superpage for DTB */
la s1, pagetable_l2_devmap
lla s1, pagetable_l2_devmap
mv s2, a1
srli s2, s2, PAGE_SHIFT
@ -152,14 +152,14 @@ _start:
/* Page tables END */
/* Setup supervisor trap vector */
la t0, va
lla t0, va
sub t0, t0, s9
li t1, KERNBASE
add t0, t0, t1
csrw stvec, t0
/* Set page tables base register */
la s2, pagetable_l1
lla s2, pagetable_l1
srli s2, s2, PAGE_SHIFT
li t0, SATP_MODE_SV39
or s2, s2, t0