[MC] [AArch64] Support resolving fixups for abs_g0 etc.

This requires a bit more code than other fixups, to distingush between
abs_g0/abs_g1/etc.  Actually, I think some of the other fixups are
missing some checks, but I won't try to address that here.

I haven't seen any real-world code that uses a construct like this, but
it clearly should work, and we're considering using it in the
implementation of localescape/localrecover on Windows (see
https://reviews.llvm.org/D53540). I've verified that binutils produces
the same code as llvm-mc for the testcase.

This currently doesn't include support for the *_s variants (that
requires a bit more work to set the opcode).

Differential Revision: https://reviews.llvm.org/D55896

llvm-svn: 349799
This commit is contained in:
Eli Friedman 2018-12-20 19:38:07 +00:00
parent b40e99af08
commit 4648209e16
3 changed files with 85 additions and 8 deletions

View File

@ -110,11 +110,11 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
case FK_Data_1:
return 1;
case AArch64::fixup_aarch64_movw:
case FK_Data_2:
case FK_SecRel_2:
return 2;
case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
@ -145,9 +145,9 @@ static unsigned AdrImmBits(unsigned Value) {
return (hi19 << 5) | (lo2 << 29);
}
static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
MCContext &Ctx, const Triple &TheTriple,
bool IsResolved) {
static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
uint64_t Value, MCContext &Ctx,
const Triple &TheTriple, bool IsResolved) {
unsigned Kind = Fixup.getKind();
int64_t SignedValue = static_cast<int64_t>(Value);
switch (Kind) {
@ -215,10 +215,51 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
if (Value & 0xf)
Ctx.reportError(Fixup.getLoc(), "fixup must be 16-byte aligned");
return Value >> 4;
case AArch64::fixup_aarch64_movw:
Ctx.reportError(Fixup.getLoc(),
"no resolvable MOVZ/MOVK fixups supported yet");
case AArch64::fixup_aarch64_movw: {
AArch64MCExpr::VariantKind RefKind =
static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS) {
if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) {
// VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't
// ever be resolved in the assembler.
Ctx.reportError(Fixup.getLoc(),
"relocation for a thread-local variable points to an "
"absolute symbol");
return Value;
}
Ctx.reportError(Fixup.getLoc(),
"resolvable R_AARCH64_MOVW_SABS_G* fixups are not "
"yet implemented");
return Value;
}
if (!IsResolved) {
// FIXME: Figure out when this can actually happen, and verify our
// behavior.
Ctx.reportError(Fixup.getLoc(), "unresolved movw fixup not yet "
"implemented");
return Value;
}
switch (AArch64MCExpr::getAddressFrag(RefKind)) {
case AArch64MCExpr::VK_G0:
break;
case AArch64MCExpr::VK_G1:
Value = Value >> 16;
break;
case AArch64MCExpr::VK_G2:
Value = Value >> 32;
break;
case AArch64MCExpr::VK_G3:
Value = Value >> 48;
break;
default:
llvm_unreachable("Variant kind doesn't correspond to fixup");
}
if (RefKind & AArch64MCExpr::VK_NC)
Value &= 0xFFFF;
else if (Value > 0xFFFF)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
return Value;
}
case AArch64::fixup_aarch64_pcrel_branch14:
// Signed 16-bit immediate
if (SignedValue > 32767 || SignedValue < -32768)
@ -296,7 +337,7 @@ void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
MCContext &Ctx = Asm.getContext();
// Apply any target-specific value adjustments.
Value = adjustFixupValue(Fixup, Value, Ctx, TheTriple, IsResolved);
Value = adjustFixupValue(Fixup, Target, Value, Ctx, TheTriple, IsResolved);
// Shift the value into position.
Value <<= Info.TargetOffset;

View File

@ -0,0 +1,21 @@
// RUN: llvm-mc -triple aarch64--none-eabi -filetype obj < %s -o - | llvm-objdump -d - | FileCheck %s
// CHECK: mov x0, #1311673391471656960
movz x0, #:abs_g3:fourpart
// CHECK: mov x0, #20014547599360
movz x0, #:abs_g2:threepart
// CHECK: movk x0, #22136, lsl #32
movk x0, #:abs_g2_nc:fourpart
// CHECK: mov x0, #305397760
movz x0, #:abs_g1:twopart
// CHECK: movk x0, #37035, lsl #16
movk x0, #:abs_g1_nc:fourpart
// CHECK: mov x0, #4660
movz x0, #:abs_g0:onepart
// CHECK: movk x0, #52719
movk x0, #:abs_g0_nc:fourpart
onepart = 0x1234
twopart = 0x12345678
threepart = 0x1234567890AB
fourpart = 0x1234567890ABCDEF

View File

@ -55,6 +55,19 @@
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup not sufficiently aligned
b unaligned
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
movz x0, #:abs_g0:value1
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
movz x0, #:abs_g1:value2
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: resolvable R_AARCH64_MOVW_SABS_G* fixups are not yet implemented
movz x0, #:abs_g0_s:value1
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: relocation for a thread-local variable points to an absolute symbol
movz x0, #:tprel_g0:value1
.byte 0
unaligned:
.byte 0
@ -63,3 +76,5 @@ unaligned:
.balign 8
distant:
.word 0
value1 = 0x12345678
value2 = 0x123456789