lld: Fix weak symbols on arm and aarch64

Given

.weak target
 .global _start
_start:
 b target

The intention is that the branch goes to the instruction after the
branch, effectively turning it on a nop.  The branch adds the runtime
PC, but we were adding it statically too.

I noticed the oddity by inspection, but llvm-objdump seems to agree,
since it now prints things like:

b       #-4 <_start+0x4>

Obtained from:  LLD commit r305212
Differential Revision:  https://reviews.freebsd.org/D11191

Reviewed by:	dim, Rafael Espíndola
Obtained from:	LLD r305212
MFC after:	3 days
This commit is contained in:
Ed Maste 2017-06-14 18:56:33 +00:00
parent dbb5554133
commit afb4d242bc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=319956

View File

@ -255,7 +255,7 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
uint32_t P) {
switch (Type) {
case R_ARM_THM_JUMP11:
return P + 2;
return P + 2 + A;
case R_ARM_CALL:
case R_ARM_JUMP24:
case R_ARM_PC24:
@ -263,12 +263,12 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
case R_ARM_PREL31:
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
return P + 4;
return P + 4 + A;
case R_ARM_THM_CALL:
// We don't want an interworking BLX to ARM
return P + 5;
return P + 5 + A;
default:
return A;
return P + A;
}
}
@ -279,9 +279,9 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
return P + 4;
return P + 4 + A;
default:
return A;
return P + A;
}
}
@ -344,20 +344,30 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
case R_PAGE_PC:
case R_PLT_PAGE_PC:
case R_PLT_PAGE_PC: {
uint64_t Dest;
if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
return getAArch64Page(A);
return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
case R_PC:
Dest = getAArch64Page(A);
else
Dest = getAArch64Page(Body.getVA<ELFT>(A));
return Dest - getAArch64Page(P);
}
case R_PC: {
uint64_t Dest;
if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
// On ARM and AArch64 a branch to an undefined weak resolves to the
// next instruction, otherwise the place.
if (Config->EMachine == EM_ARM)
return getARMUndefinedRelativeWeakVA(Type, A, P);
if (Config->EMachine == EM_AARCH64)
return getAArch64UndefinedRelativeWeakVA(Type, A, P);
Dest = getARMUndefinedRelativeWeakVA(Type, A, P);
else if (Config->EMachine == EM_AARCH64)
Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P);
else
Dest = Body.getVA<ELFT>(A);
} else {
Dest = Body.getVA<ELFT>(A);
}
return Body.getVA<ELFT>(A) - P;
return Dest - P;
}
case R_PLT:
return Body.getPltVA<ELFT>() + A;
case R_PLT_PC: