2009-08-31 10:06:59 +02:00
|
|
|
//===- MCExpr.cpp - Assembly Level Expression Implementation --------------===//
|
2009-06-29 22:40:36 +02:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2009-06-29 22:40:36 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 13:49:48 +02:00
|
|
|
#include "llvm/MC/MCExpr.h"
|
2010-03-24 00:47:14 +01:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2019-07-18 01:43:58 +02:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2010-03-16 00:51:06 +01:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2018-04-30 16:59:11 +02:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
[RISCV] Add symbol diff relocation support for RISC-V
For RISC-V it is desirable to have relaxation happen in the linker once
addresses are known, and as such the size between two instructions/byte
sequences in a section could change.
For most assembler expressions, this is fine, as the absolute address results
in the expression being converted to a fixup, and finally relocations.
However, for expressions such as .quad .L2-.L1, the assembler folds this down
to a constant once fragments are laid out, under the assumption that the
difference can no longer change, although in the case of linker relaxation the
differences can change at link time, so the constant is incorrect. One place
where this commonly appears is in debug information, where the size of a
function expression is in a form similar to the above.
This patch extends the assembler to allow an AsmBackend to declare that it
does not want the assembler to fold down this expression, and instead generate
a pair of relocations that allow the linker to carry out the calculation. In
this case, the expression is not folded, but when it comes to emitting a
fixup, the generic FK_Data_* fixups are converted into a pair, one for the
addition half, one for the subtraction, and this is passed to the relocation
generating methods as usual. I have named these FK_Data_Add_* and
FK_Data_Sub_* to indicate which half these are for.
For RISC-V, which supports this via e.g. the R_RISCV_ADD64, R_RISCV_SUB64 pair
of relocations, these are also set to always emit relocations relative to
local symbols rather than section offsets. This is to deal with the fact that
if relocations were calculated on e.g. .text+8 and .text+4, the result 12
would be stored rather than 4 as both addends are added in the linker.
Differential Revision: https://reviews.llvm.org/D45181
Patch by Simon Cook.
llvm-svn: 333079
2018-05-23 14:36:18 +02:00
|
|
|
#include "llvm/MC/MCAsmBackend.h"
|
2013-12-04 23:43:20 +01:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2010-03-11 06:53:37 +01:00
|
|
|
#include "llvm/MC/MCAsmLayout.h"
|
|
|
|
#include "llvm/MC/MCAssembler.h"
|
2009-06-29 22:40:36 +02:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2012-03-26 08:58:25 +02:00
|
|
|
#include "llvm/MC/MCObjectWriter.h"
|
2009-06-30 03:49:52 +02:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2009-06-29 22:40:36 +02:00
|
|
|
#include "llvm/MC/MCValue.h"
|
2017-02-08 00:02:00 +01:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
2010-01-05 02:28:07 +01:00
|
|
|
#include "llvm/Support/Debug.h"
|
2012-01-10 19:08:01 +01:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2009-08-31 10:07:33 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-02-08 00:02:00 +01:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
|
2009-06-29 22:40:36 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 05:04:17 +02:00
|
|
|
#define DEBUG_TYPE "mcexpr"
|
|
|
|
|
2010-03-24 00:47:14 +01:00
|
|
|
namespace {
|
|
|
|
namespace stats {
|
2017-02-08 00:02:00 +01:00
|
|
|
|
2010-03-24 00:47:14 +01:00
|
|
|
STATISTIC(MCExprEvaluate, "Number of MCExpr evaluations");
|
2017-02-08 00:02:00 +01:00
|
|
|
|
|
|
|
} // end namespace stats
|
|
|
|
} // end anonymous namespace
|
2010-03-24 00:47:14 +01:00
|
|
|
|
2016-05-03 15:35:44 +02:00
|
|
|
void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const {
|
2009-08-31 10:07:33 +02:00
|
|
|
switch (getKind()) {
|
2010-02-08 20:41:07 +01:00
|
|
|
case MCExpr::Target:
|
2015-06-09 02:31:39 +02:00
|
|
|
return cast<MCTargetExpr>(this)->printImpl(OS, MAI);
|
2019-07-18 01:43:58 +02:00
|
|
|
case MCExpr::Constant: {
|
|
|
|
auto Value = cast<MCConstantExpr>(*this).getValue();
|
|
|
|
auto PrintInHex = cast<MCConstantExpr>(*this).useHexFormat();
|
2020-02-06 17:12:10 +01:00
|
|
|
auto SizeInBytes = cast<MCConstantExpr>(*this).getSizeInBytes();
|
2020-07-08 22:23:18 +02:00
|
|
|
if (Value < 0 && MAI && !MAI->supportsSignedData())
|
|
|
|
PrintInHex = true;
|
2019-07-18 01:43:58 +02:00
|
|
|
if (PrintInHex)
|
2020-02-06 17:12:10 +01:00
|
|
|
switch (SizeInBytes) {
|
|
|
|
default:
|
|
|
|
OS << "0x" << Twine::utohexstr(Value);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
OS << format("0x%02" PRIx64, Value);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
OS << format("0x%04" PRIx64, Value);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
OS << format("0x%08" PRIx64, Value);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
OS << format("0x%016" PRIx64, Value);
|
|
|
|
break;
|
|
|
|
}
|
2019-07-18 01:43:58 +02:00
|
|
|
else
|
|
|
|
OS << Value;
|
2009-08-31 10:07:33 +02:00
|
|
|
return;
|
2019-07-18 01:43:58 +02:00
|
|
|
}
|
2009-09-09 01:20:50 +02:00
|
|
|
case MCExpr::SymbolRef: {
|
2010-03-16 00:51:06 +01:00
|
|
|
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this);
|
|
|
|
const MCSymbol &Sym = SRE.getSymbol();
|
2010-11-15 03:46:57 +01:00
|
|
|
// Parenthesize names that start with $ so that they don't look like
|
|
|
|
// absolute names.
|
2016-05-03 15:35:44 +02:00
|
|
|
bool UseParens =
|
2017-02-08 00:02:00 +01:00
|
|
|
!InParens && !Sym.getName().empty() && Sym.getName()[0] == '$';
|
2015-06-09 02:31:39 +02:00
|
|
|
if (UseParens) {
|
|
|
|
OS << '(';
|
|
|
|
Sym.print(OS, MAI);
|
|
|
|
OS << ')';
|
|
|
|
} else
|
|
|
|
Sym.print(OS, MAI);
|
2010-03-16 00:51:06 +01:00
|
|
|
|
2020-10-01 09:05:15 +02:00
|
|
|
const MCSymbolRefExpr::VariantKind Kind = SRE.getKind();
|
|
|
|
if (Kind != MCSymbolRefExpr::VK_None) {
|
|
|
|
if (MAI && MAI->useParensForSymbolVariant()) // ARM
|
|
|
|
OS << '(' << MCSymbolRefExpr::getVariantKindName(Kind) << ')';
|
|
|
|
else
|
|
|
|
OS << '@' << MCSymbolRefExpr::getVariantKindName(Kind);
|
|
|
|
}
|
2010-03-16 00:51:06 +01:00
|
|
|
|
2009-08-31 10:07:33 +02:00
|
|
|
return;
|
2009-09-09 01:20:50 +02:00
|
|
|
}
|
2009-08-31 10:07:33 +02:00
|
|
|
|
|
|
|
case MCExpr::Unary: {
|
|
|
|
const MCUnaryExpr &UE = cast<MCUnaryExpr>(*this);
|
|
|
|
switch (UE.getOpcode()) {
|
|
|
|
case MCUnaryExpr::LNot: OS << '!'; break;
|
|
|
|
case MCUnaryExpr::Minus: OS << '-'; break;
|
|
|
|
case MCUnaryExpr::Not: OS << '~'; break;
|
|
|
|
case MCUnaryExpr::Plus: OS << '+'; break;
|
|
|
|
}
|
2018-05-14 07:25:36 +02:00
|
|
|
bool Binary = UE.getSubExpr()->getKind() == MCExpr::Binary;
|
|
|
|
if (Binary) OS << "(";
|
2015-06-09 02:31:39 +02:00
|
|
|
UE.getSubExpr()->print(OS, MAI);
|
2018-05-14 07:25:36 +02:00
|
|
|
if (Binary) OS << ")";
|
2009-08-31 10:07:33 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MCExpr::Binary: {
|
|
|
|
const MCBinaryExpr &BE = cast<MCBinaryExpr>(*this);
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2009-09-08 08:34:07 +02:00
|
|
|
// Only print parens around the LHS if it is non-trivial.
|
|
|
|
if (isa<MCConstantExpr>(BE.getLHS()) || isa<MCSymbolRefExpr>(BE.getLHS())) {
|
2015-06-09 02:31:39 +02:00
|
|
|
BE.getLHS()->print(OS, MAI);
|
2009-09-08 08:34:07 +02:00
|
|
|
} else {
|
2015-06-09 02:31:39 +02:00
|
|
|
OS << '(';
|
|
|
|
BE.getLHS()->print(OS, MAI);
|
|
|
|
OS << ')';
|
2009-09-08 08:34:07 +02:00
|
|
|
}
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2009-08-31 10:07:33 +02:00
|
|
|
switch (BE.getOpcode()) {
|
2009-09-08 08:37:35 +02:00
|
|
|
case MCBinaryExpr::Add:
|
|
|
|
// Print "X-42" instead of "X+-42".
|
|
|
|
if (const MCConstantExpr *RHSC = dyn_cast<MCConstantExpr>(BE.getRHS())) {
|
|
|
|
if (RHSC->getValue() < 0) {
|
|
|
|
OS << RHSC->getValue();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2009-09-08 08:37:35 +02:00
|
|
|
OS << '+';
|
|
|
|
break;
|
2015-04-28 02:21:32 +02:00
|
|
|
case MCBinaryExpr::AShr: OS << ">>"; break;
|
2009-08-31 10:07:33 +02:00
|
|
|
case MCBinaryExpr::And: OS << '&'; break;
|
|
|
|
case MCBinaryExpr::Div: OS << '/'; break;
|
|
|
|
case MCBinaryExpr::EQ: OS << "=="; break;
|
|
|
|
case MCBinaryExpr::GT: OS << '>'; break;
|
|
|
|
case MCBinaryExpr::GTE: OS << ">="; break;
|
|
|
|
case MCBinaryExpr::LAnd: OS << "&&"; break;
|
|
|
|
case MCBinaryExpr::LOr: OS << "||"; break;
|
2015-04-28 02:21:32 +02:00
|
|
|
case MCBinaryExpr::LShr: OS << ">>"; break;
|
2009-08-31 10:07:33 +02:00
|
|
|
case MCBinaryExpr::LT: OS << '<'; break;
|
|
|
|
case MCBinaryExpr::LTE: OS << "<="; break;
|
|
|
|
case MCBinaryExpr::Mod: OS << '%'; break;
|
|
|
|
case MCBinaryExpr::Mul: OS << '*'; break;
|
|
|
|
case MCBinaryExpr::NE: OS << "!="; break;
|
|
|
|
case MCBinaryExpr::Or: OS << '|'; break;
|
2020-07-31 08:24:09 +02:00
|
|
|
case MCBinaryExpr::OrNot: OS << '!'; break;
|
2009-08-31 10:07:33 +02:00
|
|
|
case MCBinaryExpr::Shl: OS << "<<"; break;
|
|
|
|
case MCBinaryExpr::Sub: OS << '-'; break;
|
|
|
|
case MCBinaryExpr::Xor: OS << '^'; break;
|
|
|
|
}
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2009-09-08 08:34:07 +02:00
|
|
|
// Only print parens around the LHS if it is non-trivial.
|
|
|
|
if (isa<MCConstantExpr>(BE.getRHS()) || isa<MCSymbolRefExpr>(BE.getRHS())) {
|
2015-06-09 02:31:39 +02:00
|
|
|
BE.getRHS()->print(OS, MAI);
|
2009-09-08 08:34:07 +02:00
|
|
|
} else {
|
2015-06-09 02:31:39 +02:00
|
|
|
OS << '(';
|
|
|
|
BE.getRHS()->print(OS, MAI);
|
|
|
|
OS << ')';
|
2009-09-08 08:34:07 +02:00
|
|
|
}
|
2009-08-31 10:07:33 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-07 06:05:23 +01:00
|
|
|
llvm_unreachable("Invalid expression kind!");
|
2009-08-31 10:07:33 +02:00
|
|
|
}
|
|
|
|
|
2017-10-15 16:32:27 +02:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-29 21:50:44 +01:00
|
|
|
LLVM_DUMP_METHOD void MCExpr::dump() const {
|
2015-05-27 15:05:42 +02:00
|
|
|
dbgs() << *this;
|
2010-01-05 02:28:07 +01:00
|
|
|
dbgs() << '\n';
|
2009-08-31 10:07:33 +02:00
|
|
|
}
|
2017-01-28 03:02:38 +01:00
|
|
|
#endif
|
2009-08-31 10:07:33 +02:00
|
|
|
|
|
|
|
/* *** */
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
const MCBinaryExpr *MCBinaryExpr::create(Opcode Opc, const MCExpr *LHS,
|
2017-01-19 21:06:32 +01:00
|
|
|
const MCExpr *RHS, MCContext &Ctx,
|
|
|
|
SMLoc Loc) {
|
|
|
|
return new (Ctx) MCBinaryExpr(Opc, LHS, RHS, Loc);
|
2009-06-29 22:40:36 +02:00
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
const MCUnaryExpr *MCUnaryExpr::create(Opcode Opc, const MCExpr *Expr,
|
2017-03-10 14:08:20 +01:00
|
|
|
MCContext &Ctx, SMLoc Loc) {
|
|
|
|
return new (Ctx) MCUnaryExpr(Opc, Expr, Loc);
|
2009-08-31 10:07:22 +02:00
|
|
|
}
|
|
|
|
|
2019-07-18 01:43:58 +02:00
|
|
|
const MCConstantExpr *MCConstantExpr::create(int64_t Value, MCContext &Ctx,
|
2020-02-06 17:12:10 +01:00
|
|
|
bool PrintInHex,
|
|
|
|
unsigned SizeInBytes) {
|
|
|
|
return new (Ctx) MCConstantExpr(Value, PrintInHex, SizeInBytes);
|
2009-08-31 10:07:22 +02:00
|
|
|
}
|
|
|
|
|
2010-03-16 00:51:06 +01:00
|
|
|
/* *** */
|
|
|
|
|
2014-10-11 19:57:27 +02:00
|
|
|
MCSymbolRefExpr::MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind,
|
2017-01-19 21:06:32 +01:00
|
|
|
const MCAsmInfo *MAI, SMLoc Loc)
|
2020-04-10 22:06:12 +02:00
|
|
|
: MCExpr(MCExpr::SymbolRef, Loc,
|
2020-10-01 09:05:15 +02:00
|
|
|
encodeSubclassData(Kind, MAI->hasSubsectionsViaSymbols())),
|
2014-10-11 19:57:27 +02:00
|
|
|
Symbol(Symbol) {
|
|
|
|
assert(Symbol);
|
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
const MCSymbolRefExpr *MCSymbolRefExpr::create(const MCSymbol *Sym,
|
2010-03-16 00:51:06 +01:00
|
|
|
VariantKind Kind,
|
2017-01-19 21:06:32 +01:00
|
|
|
MCContext &Ctx, SMLoc Loc) {
|
|
|
|
return new (Ctx) MCSymbolRefExpr(Sym, Kind, Ctx.getAsmInfo(), Loc);
|
2009-08-31 10:07:22 +02:00
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
const MCSymbolRefExpr *MCSymbolRefExpr::create(StringRef Name, VariantKind Kind,
|
2010-03-16 00:51:06 +01:00
|
|
|
MCContext &Ctx) {
|
2015-05-30 03:25:56 +02:00
|
|
|
return create(Ctx.getOrCreateSymbol(Name), Kind, Ctx);
|
2009-09-16 03:26:31 +02:00
|
|
|
}
|
|
|
|
|
2010-03-16 00:51:06 +01:00
|
|
|
StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
|
|
|
|
switch (Kind) {
|
|
|
|
case VK_Invalid: return "<<invalid>>";
|
|
|
|
case VK_None: return "<<none>>";
|
|
|
|
|
2016-02-10 19:32:01 +01:00
|
|
|
case VK_DTPOFF: return "DTPOFF";
|
|
|
|
case VK_DTPREL: return "DTPREL";
|
2010-03-16 00:51:06 +01:00
|
|
|
case VK_GOT: return "GOT";
|
|
|
|
case VK_GOTOFF: return "GOTOFF";
|
2016-02-09 20:17:34 +01:00
|
|
|
case VK_GOTREL: return "GOTREL";
|
2020-02-19 16:47:14 +01:00
|
|
|
case VK_PCREL: return "PCREL";
|
2010-03-16 00:51:06 +01:00
|
|
|
case VK_GOTPCREL: return "GOTPCREL";
|
|
|
|
case VK_GOTTPOFF: return "GOTTPOFF";
|
|
|
|
case VK_INDNTPOFF: return "INDNTPOFF";
|
|
|
|
case VK_NTPOFF: return "NTPOFF";
|
2010-10-28 16:22:44 +02:00
|
|
|
case VK_GOTNTPOFF: return "GOTNTPOFF";
|
2010-03-16 00:51:06 +01:00
|
|
|
case VK_PLT: return "PLT";
|
|
|
|
case VK_TLSGD: return "TLSGD";
|
2010-10-28 17:02:40 +02:00
|
|
|
case VK_TLSLD: return "TLSLD";
|
2010-10-28 16:37:09 +02:00
|
|
|
case VK_TLSLDM: return "TLSLDM";
|
2010-03-16 00:51:06 +01:00
|
|
|
case VK_TPOFF: return "TPOFF";
|
2016-02-10 19:32:01 +01:00
|
|
|
case VK_TPREL: return "TPREL";
|
2016-03-15 01:25:22 +01:00
|
|
|
case VK_TLSCALL: return "tlscall";
|
2016-03-15 18:29:52 +01:00
|
|
|
case VK_TLSDESC: return "tlsdesc";
|
2010-11-14 23:22:59 +01:00
|
|
|
case VK_TLVP: return "TLVP";
|
2014-03-29 11:18:08 +01:00
|
|
|
case VK_TLVPPAGE: return "TLVPPAGE";
|
|
|
|
case VK_TLVPPAGEOFF: return "TLVPPAGEOFF";
|
|
|
|
case VK_PAGE: return "PAGE";
|
|
|
|
case VK_PAGEOFF: return "PAGEOFF";
|
|
|
|
case VK_GOTPAGE: return "GOTPAGE";
|
|
|
|
case VK_GOTPAGEOFF: return "GOTPAGEOFF";
|
2013-03-30 17:21:50 +01:00
|
|
|
case VK_SECREL: return "SECREL32";
|
2015-03-04 07:49:39 +01:00
|
|
|
case VK_SIZE: return "SIZE";
|
2014-03-20 03:12:01 +01:00
|
|
|
case VK_WEAKREF: return "WEAKREF";
|
2017-01-31 19:28:44 +01:00
|
|
|
case VK_X86_ABS8: return "ABS8";
|
2020-12-01 17:39:00 +01:00
|
|
|
case VK_X86_PLTOFF: return "PLTOFF";
|
2013-12-04 23:43:20 +01:00
|
|
|
case VK_ARM_NONE: return "none";
|
2015-10-26 19:23:16 +01:00
|
|
|
case VK_ARM_GOT_PREL: return "GOT_PREL";
|
2013-12-04 23:43:20 +01:00
|
|
|
case VK_ARM_TARGET1: return "target1";
|
|
|
|
case VK_ARM_TARGET2: return "target2";
|
|
|
|
case VK_ARM_PREL31: return "prel31";
|
2015-01-11 05:39:18 +01:00
|
|
|
case VK_ARM_SBREL: return "sbrel";
|
2014-01-20 12:00:40 +01:00
|
|
|
case VK_ARM_TLSLDO: return "tlsldo";
|
2014-01-30 05:02:47 +01:00
|
|
|
case VK_ARM_TLSDESCSEQ: return "tlsdescseq";
|
2017-12-09 09:01:28 +01:00
|
|
|
case VK_AVR_NONE: return "none";
|
|
|
|
case VK_AVR_LO8: return "lo8";
|
|
|
|
case VK_AVR_HI8: return "hi8";
|
|
|
|
case VK_AVR_HLO8: return "hlo8";
|
|
|
|
case VK_AVR_DIFF8: return "diff8";
|
|
|
|
case VK_AVR_DIFF16: return "diff16";
|
|
|
|
case VK_AVR_DIFF32: return "diff32";
|
2021-02-09 11:08:19 +01:00
|
|
|
case VK_AVR_PM: return "pm";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_LO: return "l";
|
2013-06-21 16:42:49 +02:00
|
|
|
case VK_PPC_HI: return "h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_HA: return "ha";
|
2018-06-15 21:47:11 +02:00
|
|
|
case VK_PPC_HIGH: return "high";
|
|
|
|
case VK_PPC_HIGHA: return "higha";
|
2013-06-21 16:43:42 +02:00
|
|
|
case VK_PPC_HIGHER: return "higher";
|
|
|
|
case VK_PPC_HIGHERA: return "highera";
|
|
|
|
case VK_PPC_HIGHEST: return "highest";
|
|
|
|
case VK_PPC_HIGHESTA: return "highesta";
|
2013-06-25 18:49:50 +02:00
|
|
|
case VK_PPC_GOT_LO: return "got@l";
|
|
|
|
case VK_PPC_GOT_HI: return "got@h";
|
|
|
|
case VK_PPC_GOT_HA: return "got@ha";
|
2013-06-21 00:39:42 +02:00
|
|
|
case VK_PPC_TOCBASE: return "tocbase";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_TOC: return "toc";
|
|
|
|
case VK_PPC_TOC_LO: return "toc@l";
|
2013-06-21 16:43:10 +02:00
|
|
|
case VK_PPC_TOC_HI: return "toc@h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_TOC_HA: return "toc@ha";
|
2019-10-17 15:20:25 +02:00
|
|
|
case VK_PPC_U: return "u";
|
|
|
|
case VK_PPC_L: return "l";
|
2013-07-02 01:33:29 +02:00
|
|
|
case VK_PPC_DTPMOD: return "dtpmod";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_TPREL_LO: return "tprel@l";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_TPREL_HI: return "tprel@h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_TPREL_HA: return "tprel@ha";
|
2018-06-15 21:47:16 +02:00
|
|
|
case VK_PPC_TPREL_HIGH: return "tprel@high";
|
|
|
|
case VK_PPC_TPREL_HIGHA: return "tprel@higha";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_TPREL_HIGHER: return "tprel@higher";
|
|
|
|
case VK_PPC_TPREL_HIGHERA: return "tprel@highera";
|
|
|
|
case VK_PPC_TPREL_HIGHEST: return "tprel@highest";
|
|
|
|
case VK_PPC_TPREL_HIGHESTA: return "tprel@highesta";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_DTPREL_LO: return "dtprel@l";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_DTPREL_HI: return "dtprel@h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_DTPREL_HA: return "dtprel@ha";
|
2018-06-15 21:47:16 +02:00
|
|
|
case VK_PPC_DTPREL_HIGH: return "dtprel@high";
|
|
|
|
case VK_PPC_DTPREL_HIGHA: return "dtprel@higha";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_DTPREL_HIGHER: return "dtprel@higher";
|
|
|
|
case VK_PPC_DTPREL_HIGHERA: return "dtprel@highera";
|
|
|
|
case VK_PPC_DTPREL_HIGHEST: return "dtprel@highest";
|
|
|
|
case VK_PPC_DTPREL_HIGHESTA: return "dtprel@highesta";
|
|
|
|
case VK_PPC_GOT_TPREL: return "got@tprel";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_GOT_TPREL_LO: return "got@tprel@l";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_GOT_TPREL_HI: return "got@tprel@h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_GOT_TPREL_HA: return "got@tprel@ha";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_GOT_DTPREL: return "got@dtprel";
|
|
|
|
case VK_PPC_GOT_DTPREL_LO: return "got@dtprel@l";
|
|
|
|
case VK_PPC_GOT_DTPREL_HI: return "got@dtprel@h";
|
|
|
|
case VK_PPC_GOT_DTPREL_HA: return "got@dtprel@ha";
|
2012-12-04 17:18:08 +01:00
|
|
|
case VK_PPC_TLS: return "tls";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_GOT_TLSGD: return "got@tlsgd";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_GOT_TLSGD_LO: return "got@tlsgd@l";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_GOT_TLSGD_HI: return "got@tlsgd@h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_GOT_TLSGD_HA: return "got@tlsgd@ha";
|
[PowerPC] Revert r185476 and fix up TLS variant kinds
In the commit message to r185476 I wrote:
>The PowerPC-specific modifiers VK_PPC_TLSGD and VK_PPC_TLSLD
>correspond exactly to the generic modifiers VK_TLSGD and VK_TLSLD.
>This causes some confusion with the asm parser, since VK_PPC_TLSGD
>is output as @tlsgd, which is then read back in as VK_TLSGD.
>
>To avoid this confusion, this patch removes the PowerPC-specific
>modifiers and uses the generic modifiers throughout. (The only
>drawback is that the generic modifiers are printed in upper case
>while the usual convention on PowerPC is to use lower-case modifiers.
>But this is just a cosmetic issue.)
This was unfortunately incorrect, there is is fact another,
serious drawback to using the default VK_TLSLD/VK_TLSGD
variant kinds: using these causes ELFObjectWriter::RelocNeedsGOT
to return true, which in turn causes the ELFObjectWriter to emit
an undefined reference to _GLOBAL_OFFSET_TABLE_.
This is a problem on powerpc64, because it uses the TOC instead
of the GOT, and the linker does not provide _GLOBAL_OFFSET_TABLE_,
so the symbol remains undefined. This means shared libraries
using TLS built with the integrated assembler are currently
broken.
While the whole RelocNeedsGOT / _GLOBAL_OFFSET_TABLE_ situation
probably ought to be properly fixed at some point, for now I'm
simply reverting the r185476 commit. Now this in turn exposes
the breakage of handling @tlsgd/@tlsld in the asm parser that
this check-in was originally intended to fix.
To avoid this regression, I'm also adding a different fix for
this problem: while common code now parses @tlsgd as VK_TLSGD,
a special hack in the asm parser translates this code to the
platform-specific VK_PPC_TLSGD that the back-end now expects.
While this is not really pretty, it's self-contained and
shouldn't hurt anything else for now. One the underlying
problem is fixed, this hack can be reverted again.
llvm-svn: 185945
2013-07-09 18:41:09 +02:00
|
|
|
case VK_PPC_TLSGD: return "tlsgd";
|
2021-04-28 20:57:16 +02:00
|
|
|
case VK_PPC_AIX_TLSGD:
|
|
|
|
return "gd";
|
|
|
|
case VK_PPC_AIX_TLSGDM:
|
|
|
|
return "m";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_GOT_TLSLD: return "got@tlsld";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_GOT_TLSLD_LO: return "got@tlsld@l";
|
2013-06-21 16:44:15 +02:00
|
|
|
case VK_PPC_GOT_TLSLD_HI: return "got@tlsld@h";
|
2013-06-21 16:42:20 +02:00
|
|
|
case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha";
|
2020-04-17 18:05:02 +02:00
|
|
|
case VK_PPC_GOT_PCREL:
|
|
|
|
return "got@pcrel";
|
2020-06-22 18:43:03 +02:00
|
|
|
case VK_PPC_GOT_TLSGD_PCREL:
|
|
|
|
return "got@tlsgd@pcrel";
|
2020-09-23 20:43:33 +02:00
|
|
|
case VK_PPC_GOT_TLSLD_PCREL:
|
|
|
|
return "got@tlsld@pcrel";
|
2020-06-16 18:18:38 +02:00
|
|
|
case VK_PPC_GOT_TPREL_PCREL:
|
|
|
|
return "got@tprel@pcrel";
|
|
|
|
case VK_PPC_TLS_PCREL:
|
|
|
|
return "tls@pcrel";
|
[PowerPC] Revert r185476 and fix up TLS variant kinds
In the commit message to r185476 I wrote:
>The PowerPC-specific modifiers VK_PPC_TLSGD and VK_PPC_TLSLD
>correspond exactly to the generic modifiers VK_TLSGD and VK_TLSLD.
>This causes some confusion with the asm parser, since VK_PPC_TLSGD
>is output as @tlsgd, which is then read back in as VK_TLSGD.
>
>To avoid this confusion, this patch removes the PowerPC-specific
>modifiers and uses the generic modifiers throughout. (The only
>drawback is that the generic modifiers are printed in upper case
>while the usual convention on PowerPC is to use lower-case modifiers.
>But this is just a cosmetic issue.)
This was unfortunately incorrect, there is is fact another,
serious drawback to using the default VK_TLSLD/VK_TLSGD
variant kinds: using these causes ELFObjectWriter::RelocNeedsGOT
to return true, which in turn causes the ELFObjectWriter to emit
an undefined reference to _GLOBAL_OFFSET_TABLE_.
This is a problem on powerpc64, because it uses the TOC instead
of the GOT, and the linker does not provide _GLOBAL_OFFSET_TABLE_,
so the symbol remains undefined. This means shared libraries
using TLS built with the integrated assembler are currently
broken.
While the whole RelocNeedsGOT / _GLOBAL_OFFSET_TABLE_ situation
probably ought to be properly fixed at some point, for now I'm
simply reverting the r185476 commit. Now this in turn exposes
the breakage of handling @tlsgd/@tlsld in the asm parser that
this check-in was originally intended to fix.
To avoid this regression, I'm also adding a different fix for
this problem: while common code now parses @tlsgd as VK_TLSGD,
a special hack in the asm parser translates this code to the
platform-specific VK_PPC_TLSGD that the back-end now expects.
While this is not really pretty, it's self-contained and
shouldn't hurt anything else for now. One the underlying
problem is fixed, this hack can be reverted again.
llvm-svn: 185945
2013-07-09 18:41:09 +02:00
|
|
|
case VK_PPC_TLSLD: return "tlsld";
|
2014-11-12 16:16:30 +01:00
|
|
|
case VK_PPC_LOCAL: return "local";
|
2020-04-08 15:07:35 +02:00
|
|
|
case VK_PPC_NOTOC: return "notoc";
|
[PowerPC] Add linker opt for PC Relative GOT indirect accesses
A linker optimization is available on PowerPC for GOT indirect PCRelative loads.
The idea is that we can mark a usual GOT indirect load:
pld 3, vec@got@pcrel(0), 1
lwa 3, 4(3)
With a relocation to say that if we don't need to go through the GOT we can let
the linker further optimize this and replace a load with a nop.
pld 3, vec@got@pcrel(0), 1
.Lpcrel1:
.reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
lwa 3, 4(3)
This patch adds the logic that allows the compiler to add the R_PPC64_PCREL_OPT.
Reviewers: nemanjai, lei, hfinkel, sfertile, efriedma, tstellar, grosbach
Reviewed By: nemanjai
Differential Revision: https://reviews.llvm.org/D79864
2020-07-21 21:29:54 +02:00
|
|
|
case VK_PPC_PCREL_OPT: return "<<invalid>>";
|
2014-09-25 04:09:18 +02:00
|
|
|
case VK_COFF_IMGREL32: return "IMGREL";
|
2015-05-01 23:14:21 +02:00
|
|
|
case VK_Hexagon_LO16: return "LO16";
|
|
|
|
case VK_Hexagon_HI16: return "HI16";
|
|
|
|
case VK_Hexagon_GPREL: return "GPREL";
|
|
|
|
case VK_Hexagon_GD_GOT: return "GDGOT";
|
|
|
|
case VK_Hexagon_LD_GOT: return "LDGOT";
|
|
|
|
case VK_Hexagon_GD_PLT: return "GDPLT";
|
|
|
|
case VK_Hexagon_LD_PLT: return "LDPLT";
|
|
|
|
case VK_Hexagon_IE: return "IE";
|
|
|
|
case VK_Hexagon_IE_GOT: return "IEGOT";
|
2019-04-04 19:43:50 +02:00
|
|
|
case VK_WASM_TYPEINDEX: return "TYPEINDEX";
|
|
|
|
case VK_WASM_MBREL: return "MBREL";
|
2020-11-11 02:46:52 +01:00
|
|
|
case VK_WASM_TLSREL: return "TLSREL";
|
2019-04-04 19:43:50 +02:00
|
|
|
case VK_WASM_TBREL: return "TBREL";
|
2016-10-14 06:21:32 +02:00
|
|
|
case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
|
|
|
|
case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
|
|
|
|
case VK_AMDGPU_REL32_LO: return "rel32@lo";
|
|
|
|
case VK_AMDGPU_REL32_HI: return "rel32@hi";
|
2018-06-11 23:37:57 +02:00
|
|
|
case VK_AMDGPU_REL64: return "rel64";
|
2019-06-16 19:43:37 +02:00
|
|
|
case VK_AMDGPU_ABS32_LO: return "abs32@lo";
|
|
|
|
case VK_AMDGPU_ABS32_HI: return "abs32@hi";
|
2020-07-06 20:49:59 +02:00
|
|
|
case VK_VE_HI32: return "hi";
|
|
|
|
case VK_VE_LO32: return "lo";
|
|
|
|
case VK_VE_PC_HI32: return "pc_hi";
|
|
|
|
case VK_VE_PC_LO32: return "pc_lo";
|
|
|
|
case VK_VE_GOT_HI32: return "got_hi";
|
|
|
|
case VK_VE_GOT_LO32: return "got_lo";
|
|
|
|
case VK_VE_GOTOFF_HI32: return "gotoff_hi";
|
|
|
|
case VK_VE_GOTOFF_LO32: return "gotoff_lo";
|
|
|
|
case VK_VE_PLT_HI32: return "plt_hi";
|
|
|
|
case VK_VE_PLT_LO32: return "plt_lo";
|
|
|
|
case VK_VE_TLS_GD_HI32: return "tls_gd_hi";
|
|
|
|
case VK_VE_TLS_GD_LO32: return "tls_gd_lo";
|
|
|
|
case VK_VE_TPOFF_HI32: return "tpoff_hi";
|
|
|
|
case VK_VE_TPOFF_LO32: return "tpoff_lo";
|
2010-03-16 00:51:06 +01:00
|
|
|
}
|
2012-01-10 19:08:01 +01:00
|
|
|
llvm_unreachable("Invalid variant kind");
|
2010-03-16 00:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MCSymbolRefExpr::VariantKind
|
|
|
|
MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
|
2014-12-19 00:12:34 +01:00
|
|
|
return StringSwitch<VariantKind>(Name.lower())
|
2016-02-10 19:32:01 +01:00
|
|
|
.Case("dtprel", VK_DTPREL)
|
|
|
|
.Case("dtpoff", VK_DTPOFF)
|
2011-01-23 17:11:25 +01:00
|
|
|
.Case("got", VK_GOT)
|
|
|
|
.Case("gotoff", VK_GOTOFF)
|
2016-02-09 20:17:34 +01:00
|
|
|
.Case("gotrel", VK_GOTREL)
|
2020-02-19 16:47:14 +01:00
|
|
|
.Case("pcrel", VK_PCREL)
|
2011-01-23 17:11:25 +01:00
|
|
|
.Case("gotpcrel", VK_GOTPCREL)
|
|
|
|
.Case("gottpoff", VK_GOTTPOFF)
|
|
|
|
.Case("indntpoff", VK_INDNTPOFF)
|
|
|
|
.Case("ntpoff", VK_NTPOFF)
|
|
|
|
.Case("gotntpoff", VK_GOTNTPOFF)
|
|
|
|
.Case("plt", VK_PLT)
|
2016-03-15 01:25:22 +01:00
|
|
|
.Case("tlscall", VK_TLSCALL)
|
2016-03-15 18:29:52 +01:00
|
|
|
.Case("tlsdesc", VK_TLSDESC)
|
2011-01-23 17:11:25 +01:00
|
|
|
.Case("tlsgd", VK_TLSGD)
|
|
|
|
.Case("tlsld", VK_TLSLD)
|
|
|
|
.Case("tlsldm", VK_TLSLDM)
|
|
|
|
.Case("tpoff", VK_TPOFF)
|
2016-02-10 19:32:01 +01:00
|
|
|
.Case("tprel", VK_TPREL)
|
2011-01-23 17:11:25 +01:00
|
|
|
.Case("tlvp", VK_TLVP)
|
2014-03-29 11:18:08 +01:00
|
|
|
.Case("tlvppage", VK_TLVPPAGE)
|
|
|
|
.Case("tlvppageoff", VK_TLVPPAGEOFF)
|
|
|
|
.Case("page", VK_PAGE)
|
|
|
|
.Case("pageoff", VK_PAGEOFF)
|
|
|
|
.Case("gotpage", VK_GOTPAGE)
|
|
|
|
.Case("gotpageoff", VK_GOTPAGEOFF)
|
2013-04-11 01:28:17 +02:00
|
|
|
.Case("imgrel", VK_COFF_IMGREL32)
|
2013-04-25 21:27:05 +02:00
|
|
|
.Case("secrel32", VK_SECREL)
|
2015-03-04 07:49:39 +01:00
|
|
|
.Case("size", VK_SIZE)
|
2017-01-31 19:28:44 +01:00
|
|
|
.Case("abs8", VK_X86_ABS8)
|
2020-12-01 17:39:00 +01:00
|
|
|
.Case("pltoff", VK_X86_PLTOFF)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("l", VK_PPC_LO)
|
2013-06-21 16:42:49 +02:00
|
|
|
.Case("h", VK_PPC_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("ha", VK_PPC_HA)
|
2018-06-15 21:47:11 +02:00
|
|
|
.Case("high", VK_PPC_HIGH)
|
|
|
|
.Case("higha", VK_PPC_HIGHA)
|
2013-06-21 16:43:42 +02:00
|
|
|
.Case("higher", VK_PPC_HIGHER)
|
|
|
|
.Case("highera", VK_PPC_HIGHERA)
|
|
|
|
.Case("highest", VK_PPC_HIGHEST)
|
|
|
|
.Case("highesta", VK_PPC_HIGHESTA)
|
2013-06-25 18:49:50 +02:00
|
|
|
.Case("got@l", VK_PPC_GOT_LO)
|
|
|
|
.Case("got@h", VK_PPC_GOT_HI)
|
|
|
|
.Case("got@ha", VK_PPC_GOT_HA)
|
2014-12-17 07:23:35 +01:00
|
|
|
.Case("local", VK_PPC_LOCAL)
|
2013-06-21 00:39:42 +02:00
|
|
|
.Case("tocbase", VK_PPC_TOCBASE)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("toc", VK_PPC_TOC)
|
|
|
|
.Case("toc@l", VK_PPC_TOC_LO)
|
2013-06-21 16:43:10 +02:00
|
|
|
.Case("toc@h", VK_PPC_TOC_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("toc@ha", VK_PPC_TOC_HA)
|
2019-10-17 15:20:25 +02:00
|
|
|
.Case("u", VK_PPC_U)
|
|
|
|
.Case("l", VK_PPC_L)
|
2013-05-03 21:52:35 +02:00
|
|
|
.Case("tls", VK_PPC_TLS)
|
2013-07-02 01:33:29 +02:00
|
|
|
.Case("dtpmod", VK_PPC_DTPMOD)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("tprel@l", VK_PPC_TPREL_LO)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("tprel@h", VK_PPC_TPREL_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("tprel@ha", VK_PPC_TPREL_HA)
|
2018-06-15 21:47:16 +02:00
|
|
|
.Case("tprel@high", VK_PPC_TPREL_HIGH)
|
|
|
|
.Case("tprel@higha", VK_PPC_TPREL_HIGHA)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("tprel@higher", VK_PPC_TPREL_HIGHER)
|
|
|
|
.Case("tprel@highera", VK_PPC_TPREL_HIGHERA)
|
|
|
|
.Case("tprel@highest", VK_PPC_TPREL_HIGHEST)
|
|
|
|
.Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("dtprel@l", VK_PPC_DTPREL_LO)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("dtprel@h", VK_PPC_DTPREL_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("dtprel@ha", VK_PPC_DTPREL_HA)
|
2018-06-15 21:47:16 +02:00
|
|
|
.Case("dtprel@high", VK_PPC_DTPREL_HIGH)
|
|
|
|
.Case("dtprel@higha", VK_PPC_DTPREL_HIGHA)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("dtprel@higher", VK_PPC_DTPREL_HIGHER)
|
|
|
|
.Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA)
|
|
|
|
.Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST)
|
|
|
|
.Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA)
|
|
|
|
.Case("got@tprel", VK_PPC_GOT_TPREL)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("got@tprel@l", VK_PPC_GOT_TPREL_LO)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("got@tprel@h", VK_PPC_GOT_TPREL_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("got@dtprel", VK_PPC_GOT_DTPREL)
|
|
|
|
.Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO)
|
|
|
|
.Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI)
|
|
|
|
.Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA)
|
|
|
|
.Case("got@tlsgd", VK_PPC_GOT_TLSGD)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("got@tlsld", VK_PPC_GOT_TLSLD)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO)
|
2013-06-21 16:44:15 +02:00
|
|
|
.Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI)
|
2013-06-21 16:42:20 +02:00
|
|
|
.Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA)
|
2020-05-06 12:19:09 +02:00
|
|
|
.Case("got@pcrel", VK_PPC_GOT_PCREL)
|
2020-06-22 18:43:03 +02:00
|
|
|
.Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL)
|
2020-09-23 20:43:33 +02:00
|
|
|
.Case("got@tlsld@pcrel", VK_PPC_GOT_TLSLD_PCREL)
|
2020-06-16 18:18:38 +02:00
|
|
|
.Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL)
|
|
|
|
.Case("tls@pcrel", VK_PPC_TLS_PCREL)
|
2020-04-08 15:07:35 +02:00
|
|
|
.Case("notoc", VK_PPC_NOTOC)
|
2015-12-18 19:47:27 +01:00
|
|
|
.Case("gdgot", VK_Hexagon_GD_GOT)
|
|
|
|
.Case("gdplt", VK_Hexagon_GD_PLT)
|
|
|
|
.Case("iegot", VK_Hexagon_IE_GOT)
|
|
|
|
.Case("ie", VK_Hexagon_IE)
|
|
|
|
.Case("ldgot", VK_Hexagon_LD_GOT)
|
|
|
|
.Case("ldplt", VK_Hexagon_LD_PLT)
|
2013-12-04 23:43:20 +01:00
|
|
|
.Case("none", VK_ARM_NONE)
|
2015-10-26 19:23:16 +01:00
|
|
|
.Case("got_prel", VK_ARM_GOT_PREL)
|
2013-12-04 23:43:20 +01:00
|
|
|
.Case("target1", VK_ARM_TARGET1)
|
|
|
|
.Case("target2", VK_ARM_TARGET2)
|
|
|
|
.Case("prel31", VK_ARM_PREL31)
|
2015-01-11 05:39:18 +01:00
|
|
|
.Case("sbrel", VK_ARM_SBREL)
|
2014-01-20 12:00:40 +01:00
|
|
|
.Case("tlsldo", VK_ARM_TLSLDO)
|
2017-12-09 09:01:28 +01:00
|
|
|
.Case("lo8", VK_AVR_LO8)
|
|
|
|
.Case("hi8", VK_AVR_HI8)
|
|
|
|
.Case("hlo8", VK_AVR_HLO8)
|
2019-04-04 19:43:50 +02:00
|
|
|
.Case("typeindex", VK_WASM_TYPEINDEX)
|
|
|
|
.Case("tbrel", VK_WASM_TBREL)
|
|
|
|
.Case("mbrel", VK_WASM_MBREL)
|
2020-11-11 02:46:52 +01:00
|
|
|
.Case("tlsrel", VK_WASM_TLSREL)
|
2016-10-14 06:21:32 +02:00
|
|
|
.Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
|
|
|
|
.Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
|
|
|
|
.Case("rel32@lo", VK_AMDGPU_REL32_LO)
|
|
|
|
.Case("rel32@hi", VK_AMDGPU_REL32_HI)
|
2018-06-11 23:37:57 +02:00
|
|
|
.Case("rel64", VK_AMDGPU_REL64)
|
2019-06-16 19:43:37 +02:00
|
|
|
.Case("abs32@lo", VK_AMDGPU_ABS32_LO)
|
|
|
|
.Case("abs32@hi", VK_AMDGPU_ABS32_HI)
|
2020-07-06 20:49:59 +02:00
|
|
|
.Case("hi", VK_VE_HI32)
|
|
|
|
.Case("lo", VK_VE_LO32)
|
|
|
|
.Case("pc_hi", VK_VE_PC_HI32)
|
|
|
|
.Case("pc_lo", VK_VE_PC_LO32)
|
|
|
|
.Case("got_hi", VK_VE_GOT_HI32)
|
|
|
|
.Case("got_lo", VK_VE_GOT_LO32)
|
|
|
|
.Case("gotoff_hi", VK_VE_GOTOFF_HI32)
|
|
|
|
.Case("gotoff_lo", VK_VE_GOTOFF_LO32)
|
|
|
|
.Case("plt_hi", VK_VE_PLT_HI32)
|
|
|
|
.Case("plt_lo", VK_VE_PLT_LO32)
|
|
|
|
.Case("tls_gd_hi", VK_VE_TLS_GD_HI32)
|
|
|
|
.Case("tls_gd_lo", VK_VE_TLS_GD_LO32)
|
|
|
|
.Case("tpoff_hi", VK_VE_TPOFF_HI32)
|
|
|
|
.Case("tpoff_lo", VK_VE_TPOFF_LO32)
|
2010-03-16 00:51:06 +01:00
|
|
|
.Default(VK_Invalid);
|
2010-03-10 03:25:11 +01:00
|
|
|
}
|
|
|
|
|
2010-03-16 00:51:06 +01:00
|
|
|
/* *** */
|
|
|
|
|
2012-09-26 08:36:36 +02:00
|
|
|
void MCTargetExpr::anchor() {}
|
2009-09-16 03:26:31 +02:00
|
|
|
|
2009-08-31 10:07:22 +02:00
|
|
|
/* *** */
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
bool MCExpr::evaluateAsAbsolute(int64_t &Res) const {
|
2019-08-20 09:42:04 +02:00
|
|
|
return evaluateAsAbsolute(Res, nullptr, nullptr, nullptr, false);
|
2010-12-18 04:57:21 +01:00
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
bool MCExpr::evaluateAsAbsolute(int64_t &Res,
|
2010-12-18 04:57:21 +01:00
|
|
|
const MCAsmLayout &Layout) const {
|
2019-08-20 09:42:04 +02:00
|
|
|
return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, false);
|
2010-12-18 04:57:21 +01:00
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
bool MCExpr::evaluateAsAbsolute(int64_t &Res,
|
2010-12-18 04:57:21 +01:00
|
|
|
const MCAsmLayout &Layout,
|
|
|
|
const SectionAddrMap &Addrs) const {
|
2019-08-20 09:42:04 +02:00
|
|
|
// Setting InSet causes us to absolutize differences across sections and that
|
|
|
|
// is what the MachO writer uses Addrs for.
|
|
|
|
return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs, true);
|
2010-12-18 04:57:21 +01:00
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const {
|
2019-08-20 09:42:04 +02:00
|
|
|
return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr, false);
|
2010-12-18 04:57:21 +01:00
|
|
|
}
|
|
|
|
|
[MC] Change AsmParser to leverage Assembler during evaluation
Teach AsmParser to check with Assembler for when evaluating constant
expressions. This improves the handing of preprocessor expressions
that must be resolved at parse time. This idiom can be found as
assembling-time assertion checks in source-level assemblers. Note that
this relies on the MCStreamer to keep sufficient tabs on Section /
Fragment information which the MCAsmStreamer does not. As a result the
textual output may fail where the equivalent object generation would
pass. This can most easily be resolved by folding the MCAsmStreamer
and MCObjectStreamer together which is planned for in a separate
patch.
Currently, this feature is only enabled for assembly input, keeping IR
compilation consistent between assembly and object generation.
Reviewers: echristo, rnk, probinson, espindola, peter.smith
Reviewed By: peter.smith
Subscribers: eraman, peter.smith, arichardson, jyknight, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D45164
llvm-svn: 331218
2018-04-30 21:22:40 +02:00
|
|
|
bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const {
|
2019-08-20 09:42:04 +02:00
|
|
|
return evaluateAsAbsolute(Res, Asm, nullptr, nullptr, false);
|
[MC] Change AsmParser to leverage Assembler during evaluation
Teach AsmParser to check with Assembler for when evaluating constant
expressions. This improves the handing of preprocessor expressions
that must be resolved at parse time. This idiom can be found as
assembling-time assertion checks in source-level assemblers. Note that
this relies on the MCStreamer to keep sufficient tabs on Section /
Fragment information which the MCAsmStreamer does not. As a result the
textual output may fail where the equivalent object generation would
pass. This can most easily be resolved by folding the MCAsmStreamer
and MCObjectStreamer together which is planned for in a separate
patch.
Currently, this feature is only enabled for assembly input, keeping IR
compilation consistent between assembly and object generation.
Reviewers: echristo, rnk, probinson, espindola, peter.smith
Reviewed By: peter.smith
Subscribers: eraman, peter.smith, arichardson, jyknight, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D45164
llvm-svn: 331218
2018-04-30 21:22:40 +02:00
|
|
|
}
|
|
|
|
|
2015-03-25 01:25:37 +01:00
|
|
|
bool MCExpr::evaluateKnownAbsolute(int64_t &Res,
|
|
|
|
const MCAsmLayout &Layout) const {
|
|
|
|
return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr,
|
|
|
|
true);
|
2014-08-15 16:20:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
|
|
|
|
const MCAsmLayout *Layout,
|
|
|
|
const SectionAddrMap *Addrs, bool InSet) const {
|
2009-06-30 03:49:52 +02:00
|
|
|
MCValue Value;
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2010-03-24 00:47:07 +01:00
|
|
|
// Fast path constants.
|
|
|
|
if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(this)) {
|
|
|
|
Res = CE->getValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-25 14:16:53 +01:00
|
|
|
bool IsRelocatable =
|
2015-05-30 03:25:56 +02:00
|
|
|
evaluateAsRelocatableImpl(Value, Asm, Layout, nullptr, Addrs, InSet);
|
2009-06-30 03:49:52 +02:00
|
|
|
|
2010-12-22 23:16:24 +01:00
|
|
|
// Record the current value.
|
2009-06-30 03:49:52 +02:00
|
|
|
Res = Value.getConstant();
|
2010-12-22 23:16:24 +01:00
|
|
|
|
|
|
|
return IsRelocatable && Value.isAbsolute();
|
2009-06-30 03:49:52 +02:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Helper method for \see EvaluateSymbolAdd().
|
2015-03-25 20:24:39 +01:00
|
|
|
static void AttemptToFoldSymbolOffsetDifference(
|
|
|
|
const MCAssembler *Asm, const MCAsmLayout *Layout,
|
|
|
|
const SectionAddrMap *Addrs, bool InSet, const MCSymbolRefExpr *&A,
|
|
|
|
const MCSymbolRefExpr *&B, int64_t &Addend) {
|
2010-12-19 05:18:56 +01:00
|
|
|
if (!A || !B)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const MCSymbol &SA = A->getSymbol();
|
|
|
|
const MCSymbol &SB = B->getSymbol();
|
|
|
|
|
|
|
|
if (SA.isUndefined() || SB.isUndefined())
|
|
|
|
return;
|
2010-12-17 06:50:33 +01:00
|
|
|
|
2015-06-05 00:24:41 +02:00
|
|
|
if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet))
|
2010-12-19 05:18:56 +01:00
|
|
|
return;
|
|
|
|
|
2020-09-09 20:58:22 +02:00
|
|
|
auto FinalizeFolding = [&]() {
|
2011-03-22 00:13:43 +01:00
|
|
|
// Pointers to Thumb symbols need to have their low-bit set to allow
|
|
|
|
// for interworking.
|
|
|
|
if (Asm->isThumbFunc(&SA))
|
|
|
|
Addend |= 1;
|
|
|
|
|
2018-10-16 10:27:28 +02:00
|
|
|
// If symbol is labeled as micromips, we set low-bit to ensure
|
|
|
|
// correct offset in .gcc_except_table
|
|
|
|
if (Asm->getBackend().isMicroMips(&SA))
|
|
|
|
Addend |= 1;
|
|
|
|
|
2010-12-17 06:50:33 +01:00
|
|
|
// Clear the symbol expr pointers to indicate we have folded these
|
|
|
|
// operands.
|
2014-04-13 06:57:38 +02:00
|
|
|
A = B = nullptr;
|
2020-09-09 20:58:22 +02:00
|
|
|
};
|
2010-12-19 05:18:56 +01:00
|
|
|
|
2020-09-09 20:58:22 +02:00
|
|
|
const MCFragment *FA = SA.getFragment();
|
|
|
|
const MCFragment *FB = SB.getFragment();
|
|
|
|
// If both symbols are in the same fragment, return the difference of their
|
|
|
|
// offsets
|
|
|
|
if (FA == FB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() &&
|
|
|
|
!SB.isUnset()) {
|
|
|
|
Addend += SA.getOffset() - SB.getOffset();
|
|
|
|
return FinalizeFolding();
|
|
|
|
}
|
2010-12-19 05:18:56 +01:00
|
|
|
|
2020-05-05 20:11:04 +02:00
|
|
|
const MCSection &SecA = *FA->getParent();
|
|
|
|
const MCSection &SecB = *FB->getParent();
|
2010-12-19 05:18:56 +01:00
|
|
|
|
|
|
|
if ((&SecA != &SecB) && !Addrs)
|
|
|
|
return;
|
|
|
|
|
2020-09-09 20:58:22 +02:00
|
|
|
if (Layout) {
|
|
|
|
// One of the symbol involved is part of a fragment being laid out. Quit now
|
|
|
|
// to avoid a self loop.
|
|
|
|
if (!Layout->canGetFragmentOffset(FA) || !Layout->canGetFragmentOffset(FB))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Eagerly evaluate when layout is finalized.
|
|
|
|
Addend += Layout->getSymbolOffset(A->getSymbol()) -
|
|
|
|
Layout->getSymbolOffset(B->getSymbol());
|
|
|
|
if (Addrs && (&SecA != &SecB))
|
|
|
|
Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB));
|
|
|
|
|
|
|
|
FinalizeFolding();
|
|
|
|
} else {
|
|
|
|
// When layout is not finalized, our ability to resolve differences between
|
|
|
|
// symbols is limited to specific cases where the fragments between two
|
|
|
|
// symbols (including the fragments the symbols are defined in) are
|
|
|
|
// fixed-size fragments so the difference can be calculated. For example,
|
|
|
|
// this is important when the Subtarget is changed and a new MCDataFragment
|
|
|
|
// is created in the case of foo: instr; .arch_extension ext; instr .if . -
|
|
|
|
// foo.
|
|
|
|
if (SA.isVariable() || SA.isUnset() || SB.isVariable() || SB.isUnset() ||
|
|
|
|
FA->getKind() != MCFragment::FT_Data ||
|
|
|
|
FB->getKind() != MCFragment::FT_Data ||
|
|
|
|
FA->getSubsectionNumber() != FB->getSubsectionNumber())
|
|
|
|
return;
|
|
|
|
// Try to find a constant displacement from FA to FB, add the displacement
|
|
|
|
// between the offset in FA of SA and the offset in FB of SB.
|
|
|
|
int64_t Displacement = SA.getOffset() - SB.getOffset();
|
|
|
|
for (auto FI = FB->getIterator(), FE = SecA.end(); FI != FE; ++FI) {
|
|
|
|
if (&*FI == FA) {
|
|
|
|
Addend += Displacement;
|
|
|
|
return FinalizeFolding();
|
|
|
|
}
|
2020-05-05 20:11:04 +02:00
|
|
|
|
2020-09-09 20:58:22 +02:00
|
|
|
if (FI->getKind() != MCFragment::FT_Data)
|
|
|
|
return;
|
|
|
|
Displacement += cast<MCDataFragment>(FI)->getContents().size();
|
|
|
|
}
|
|
|
|
}
|
2010-12-17 06:50:33 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Evaluate the result of an add between (conceptually) two MCValues.
|
2010-12-16 19:36:25 +01:00
|
|
|
///
|
|
|
|
/// This routine conceptually attempts to construct an MCValue:
|
|
|
|
/// Result = (Result_A - Result_B + Result_Cst)
|
|
|
|
/// from two MCValue's LHS and RHS where
|
|
|
|
/// Result = LHS + RHS
|
|
|
|
/// and
|
|
|
|
/// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
|
|
|
|
///
|
2020-01-06 11:15:44 +01:00
|
|
|
/// This routine attempts to aggressively fold the operands such that the result
|
2010-12-16 19:36:25 +01:00
|
|
|
/// is representable in an MCValue, but may not always succeed.
|
|
|
|
///
|
|
|
|
/// \returns True on success, false if the result is not representable in an
|
|
|
|
/// MCValue.
|
2010-12-18 04:57:21 +01:00
|
|
|
|
|
|
|
/// NOTE: It is really important to have both the Asm and Layout arguments.
|
|
|
|
/// They might look redundant, but this function can be used before layout
|
|
|
|
/// is done (see the object streamer for example) and having the Asm argument
|
2010-12-18 05:01:45 +01:00
|
|
|
/// lets us avoid relaxations early.
|
2015-03-25 20:24:39 +01:00
|
|
|
static bool
|
|
|
|
EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout,
|
|
|
|
const SectionAddrMap *Addrs, bool InSet, const MCValue &LHS,
|
|
|
|
const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B,
|
|
|
|
int64_t RHS_Cst, MCValue &Res) {
|
2010-12-17 02:07:20 +01:00
|
|
|
// FIXME: This routine (and other evaluation parts) are *incredibly* sloppy
|
|
|
|
// about dealing with modifiers. This will ultimately bite us, one day.
|
|
|
|
const MCSymbolRefExpr *LHS_A = LHS.getSymA();
|
|
|
|
const MCSymbolRefExpr *LHS_B = LHS.getSymB();
|
|
|
|
int64_t LHS_Cst = LHS.getConstant();
|
|
|
|
|
|
|
|
// Fold the result constant immediately.
|
|
|
|
int64_t Result_Cst = LHS_Cst + RHS_Cst;
|
|
|
|
|
2010-12-19 05:18:56 +01:00
|
|
|
assert((!Layout || Asm) &&
|
|
|
|
"Must have an assembler object if layout is given!");
|
|
|
|
|
2021-05-26 17:41:11 +02:00
|
|
|
// If we have a layout, we can fold resolved differences.
|
|
|
|
if (Asm) {
|
2010-12-17 06:50:33 +01:00
|
|
|
// First, fold out any differences which are fully resolved. By
|
|
|
|
// reassociating terms in
|
|
|
|
// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
|
|
|
|
// we have the four possible differences:
|
|
|
|
// (LHS_A - LHS_B),
|
|
|
|
// (LHS_A - RHS_B),
|
|
|
|
// (RHS_A - LHS_B),
|
|
|
|
// (RHS_A - RHS_B).
|
2011-04-15 07:18:47 +02:00
|
|
|
// Since we are attempting to be as aggressive as possible about folding, we
|
2010-12-17 06:50:33 +01:00
|
|
|
// attempt to evaluate each possible alternative.
|
2010-12-19 05:18:56 +01:00
|
|
|
AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B,
|
|
|
|
Result_Cst);
|
|
|
|
AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B,
|
|
|
|
Result_Cst);
|
|
|
|
AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B,
|
|
|
|
Result_Cst);
|
|
|
|
AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B,
|
|
|
|
Result_Cst);
|
2010-12-17 06:50:33 +01:00
|
|
|
}
|
|
|
|
|
2010-12-17 02:07:20 +01:00
|
|
|
// We can't represent the addition or subtraction of two symbols.
|
|
|
|
if ((LHS_A && RHS_A) || (LHS_B && RHS_B))
|
2009-06-30 04:08:27 +02:00
|
|
|
return false;
|
|
|
|
|
2010-12-17 06:50:33 +01:00
|
|
|
// At this point, we have at most one additive symbol and one subtractive
|
|
|
|
// symbol -- find them.
|
2010-12-17 02:07:20 +01:00
|
|
|
const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A;
|
|
|
|
const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B;
|
2010-12-17 06:50:33 +01:00
|
|
|
|
2010-12-17 02:07:20 +01:00
|
|
|
Res = MCValue::get(A, B, Result_Cst);
|
2009-06-30 04:08:27 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
bool MCExpr::evaluateAsRelocatable(MCValue &Res,
|
2014-08-10 13:35:12 +02:00
|
|
|
const MCAsmLayout *Layout,
|
2014-08-10 13:37:07 +02:00
|
|
|
const MCFixup *Fixup) const {
|
2014-04-13 06:57:38 +02:00
|
|
|
MCAssembler *Assembler = Layout ? &Layout->getAssembler() : nullptr;
|
2015-05-30 03:25:56 +02:00
|
|
|
return evaluateAsRelocatableImpl(Res, Assembler, Layout, Fixup, nullptr,
|
2015-03-25 14:16:53 +01:00
|
|
|
false);
|
2010-12-18 04:57:21 +01:00
|
|
|
}
|
|
|
|
|
2015-03-26 22:11:00 +01:00
|
|
|
bool MCExpr::evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const {
|
|
|
|
MCAssembler *Assembler = &Layout.getAssembler();
|
2015-05-30 03:25:56 +02:00
|
|
|
return evaluateAsRelocatableImpl(Res, Assembler, &Layout, nullptr, nullptr,
|
2015-03-26 22:11:00 +01:00
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
2015-10-05 14:07:05 +02:00
|
|
|
static bool canExpand(const MCSymbol &Sym, bool InSet) {
|
2015-06-03 23:52:06 +02:00
|
|
|
const MCExpr *Expr = Sym.getVariableValue();
|
|
|
|
const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr);
|
|
|
|
if (Inner) {
|
|
|
|
if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-26 22:11:00 +01:00
|
|
|
if (InSet)
|
|
|
|
return true;
|
2015-10-05 14:07:05 +02:00
|
|
|
return !Sym.isInSection();
|
2014-04-28 22:53:11 +02:00
|
|
|
}
|
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
|
2010-10-16 20:23:53 +02:00
|
|
|
const MCAsmLayout *Layout,
|
2014-08-10 13:35:12 +02:00
|
|
|
const MCFixup *Fixup,
|
2015-03-25 14:16:53 +01:00
|
|
|
const SectionAddrMap *Addrs,
|
|
|
|
bool InSet) const {
|
2010-03-24 00:47:14 +01:00
|
|
|
++stats::MCExprEvaluate;
|
|
|
|
|
2009-06-29 22:40:36 +02:00
|
|
|
switch (getKind()) {
|
2010-02-08 20:41:07 +01:00
|
|
|
case Target:
|
2015-05-30 03:25:56 +02:00
|
|
|
return cast<MCTargetExpr>(this)->evaluateAsRelocatableImpl(Res, Layout,
|
2014-08-10 13:35:12 +02:00
|
|
|
Fixup);
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2009-06-29 22:40:36 +02:00
|
|
|
case Constant:
|
2009-08-31 10:06:59 +02:00
|
|
|
Res = MCValue::get(cast<MCConstantExpr>(this)->getValue());
|
2009-06-29 22:40:36 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
case SymbolRef: {
|
2010-03-18 01:59:10 +01:00
|
|
|
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
|
|
|
|
const MCSymbol &Sym = SRE->getSymbol();
|
MCExpr::evaluateAsRelocatableImpl : allow evaluation of non-VK_None MCSymbolRefExpr when MCAsmLayout is available
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4acf8c78e659833be8be047ba2f8561386a11d4b
(1994) introduced this behavior:
if a fixup symbol is equated to an expression with an undefined symbol, convert
the fixup to be against the target symbol. glibc relies on this behavior to perform
assembly level indirection
```
asm("memcpy = __GI_memcpy"); // from sysdeps/generic/symbol-hacks.h
...
// call memcpy@PLT
// The relocation references __GI_memcpy in GNU as, but memcpy in MC (without the patch)
memcpy (...);
```
(1) It complements `extern __typeof(memcpy) memcpy asm("__GI_memcpy");` The frontend asm label does not redirect synthesized memcpy in the middle-end. (See D88712 for details)
(2) `asm("memcpy = __GI_memcpy");` is in every translation unit, but the memcpy declaration may not be visible in the translation unit where memcpy is synthesized.
MC already redirects `memcpy = __GI_memcpy; call memcpy` but not `memcpy = __GI_memcpy; call memcpy@plt`.
This patch fixes the latter by allowing MCExpr::evaluateAsRelocatableImpl to
evaluate a non-VK_None MCSymbolRefExpr, which is only done after the layout is available.
GNU as allows `memcpy = __GI_memcpy+1; call memcpy@PLT` which seems nonsensical, so we don't allow it.
`MC/PowerPC/pr38945.s` `NUMBER = 0x6ffffff9; cmpwi 8,NUMBER@l` requires the
`symbol@l` form in AsmMatcher, so evaluation needs to be deferred. This is the
place whether future simplification may be possible.
Note, if we suppress the VM_None evaluation when MCAsmLayout is nullptr, we may
lose the `invalid reassignment of non-absolute variable` diagnostic
(`ARM/thumb_set-diagnostics.s` and `MC/AsmParser/variables-invalid.s`).
We know that this diagnostic is troublesome in some cases
(https://github.com/ClangBuiltLinux/linux/issues/1008), so we can consider
making simplification in the future.
Reviewed By: jyknight
Differential Revision: https://reviews.llvm.org/D88625
2020-11-18 22:52:33 +01:00
|
|
|
const auto Kind = SRE->getKind();
|
2009-10-16 03:33:57 +02:00
|
|
|
|
|
|
|
// Evaluate recursively if this is a variable.
|
MCExpr::evaluateAsRelocatableImpl : allow evaluation of non-VK_None MCSymbolRefExpr when MCAsmLayout is available
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4acf8c78e659833be8be047ba2f8561386a11d4b
(1994) introduced this behavior:
if a fixup symbol is equated to an expression with an undefined symbol, convert
the fixup to be against the target symbol. glibc relies on this behavior to perform
assembly level indirection
```
asm("memcpy = __GI_memcpy"); // from sysdeps/generic/symbol-hacks.h
...
// call memcpy@PLT
// The relocation references __GI_memcpy in GNU as, but memcpy in MC (without the patch)
memcpy (...);
```
(1) It complements `extern __typeof(memcpy) memcpy asm("__GI_memcpy");` The frontend asm label does not redirect synthesized memcpy in the middle-end. (See D88712 for details)
(2) `asm("memcpy = __GI_memcpy");` is in every translation unit, but the memcpy declaration may not be visible in the translation unit where memcpy is synthesized.
MC already redirects `memcpy = __GI_memcpy; call memcpy` but not `memcpy = __GI_memcpy; call memcpy@plt`.
This patch fixes the latter by allowing MCExpr::evaluateAsRelocatableImpl to
evaluate a non-VK_None MCSymbolRefExpr, which is only done after the layout is available.
GNU as allows `memcpy = __GI_memcpy+1; call memcpy@PLT` which seems nonsensical, so we don't allow it.
`MC/PowerPC/pr38945.s` `NUMBER = 0x6ffffff9; cmpwi 8,NUMBER@l` requires the
`symbol@l` form in AsmMatcher, so evaluation needs to be deferred. This is the
place whether future simplification may be possible.
Note, if we suppress the VM_None evaluation when MCAsmLayout is nullptr, we may
lose the `invalid reassignment of non-absolute variable` diagnostic
(`ARM/thumb_set-diagnostics.s` and `MC/AsmParser/variables-invalid.s`).
We know that this diagnostic is troublesome in some cases
(https://github.com/ClangBuiltLinux/linux/issues/1008), so we can consider
making simplification in the future.
Reviewed By: jyknight
Differential Revision: https://reviews.llvm.org/D88625
2020-11-18 22:52:33 +01:00
|
|
|
if (Sym.isVariable() && (Kind == MCSymbolRefExpr::VK_None || Layout) &&
|
2015-10-05 14:07:05 +02:00
|
|
|
canExpand(Sym, InSet)) {
|
2015-03-26 22:11:00 +01:00
|
|
|
bool IsMachO = SRE->hasSubsectionsViaSymbols();
|
2015-05-30 03:25:56 +02:00
|
|
|
if (Sym.getVariableValue()->evaluateAsRelocatableImpl(
|
2015-03-26 22:11:00 +01:00
|
|
|
Res, Asm, Layout, Fixup, Addrs, InSet || IsMachO)) {
|
MCExpr::evaluateAsRelocatableImpl : allow evaluation of non-VK_None MCSymbolRefExpr when MCAsmLayout is available
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4acf8c78e659833be8be047ba2f8561386a11d4b
(1994) introduced this behavior:
if a fixup symbol is equated to an expression with an undefined symbol, convert
the fixup to be against the target symbol. glibc relies on this behavior to perform
assembly level indirection
```
asm("memcpy = __GI_memcpy"); // from sysdeps/generic/symbol-hacks.h
...
// call memcpy@PLT
// The relocation references __GI_memcpy in GNU as, but memcpy in MC (without the patch)
memcpy (...);
```
(1) It complements `extern __typeof(memcpy) memcpy asm("__GI_memcpy");` The frontend asm label does not redirect synthesized memcpy in the middle-end. (See D88712 for details)
(2) `asm("memcpy = __GI_memcpy");` is in every translation unit, but the memcpy declaration may not be visible in the translation unit where memcpy is synthesized.
MC already redirects `memcpy = __GI_memcpy; call memcpy` but not `memcpy = __GI_memcpy; call memcpy@plt`.
This patch fixes the latter by allowing MCExpr::evaluateAsRelocatableImpl to
evaluate a non-VK_None MCSymbolRefExpr, which is only done after the layout is available.
GNU as allows `memcpy = __GI_memcpy+1; call memcpy@PLT` which seems nonsensical, so we don't allow it.
`MC/PowerPC/pr38945.s` `NUMBER = 0x6ffffff9; cmpwi 8,NUMBER@l` requires the
`symbol@l` form in AsmMatcher, so evaluation needs to be deferred. This is the
place whether future simplification may be possible.
Note, if we suppress the VM_None evaluation when MCAsmLayout is nullptr, we may
lose the `invalid reassignment of non-absolute variable` diagnostic
(`ARM/thumb_set-diagnostics.s` and `MC/AsmParser/variables-invalid.s`).
We know that this diagnostic is troublesome in some cases
(https://github.com/ClangBuiltLinux/linux/issues/1008), so we can consider
making simplification in the future.
Reviewed By: jyknight
Differential Revision: https://reviews.llvm.org/D88625
2020-11-18 22:52:33 +01:00
|
|
|
if (Kind != MCSymbolRefExpr::VK_None) {
|
|
|
|
if (Res.isAbsolute()) {
|
|
|
|
Res = MCValue::get(SRE, nullptr, 0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// If the reference has a variant kind, we can only handle expressions
|
|
|
|
// which evaluate exactly to a single unadorned symbol. Attach the
|
|
|
|
// original VariantKind to SymA of the result.
|
|
|
|
if (Res.getRefKind() != MCSymbolRefExpr::VK_None || !Res.getSymA() ||
|
|
|
|
Res.getSymB() || Res.getConstant())
|
|
|
|
return false;
|
|
|
|
Res =
|
|
|
|
MCValue::get(MCSymbolRefExpr::create(&Res.getSymA()->getSymbol(),
|
|
|
|
Kind, Asm->getContext()),
|
|
|
|
Res.getSymB(), Res.getConstant(), Res.getRefKind());
|
|
|
|
}
|
2015-03-26 22:11:00 +01:00
|
|
|
if (!IsMachO)
|
2015-03-25 14:16:53 +01:00
|
|
|
return true;
|
|
|
|
|
2014-03-20 03:12:01 +01:00
|
|
|
const MCSymbolRefExpr *A = Res.getSymA();
|
|
|
|
const MCSymbolRefExpr *B = Res.getSymB();
|
2015-03-25 14:16:53 +01:00
|
|
|
// FIXME: This is small hack. Given
|
|
|
|
// a = b + 4
|
|
|
|
// .long a
|
|
|
|
// the OS X assembler will completely drop the 4. We should probably
|
|
|
|
// include it in the relocation or produce an error if that is not
|
|
|
|
// possible.
|
2017-06-08 22:49:03 +02:00
|
|
|
// Allow constant expressions.
|
2015-03-25 14:16:53 +01:00
|
|
|
if (!A && !B)
|
|
|
|
return true;
|
2017-06-08 22:49:03 +02:00
|
|
|
// Allows aliases with zero offset.
|
|
|
|
if (Res.getConstant() == 0 && (!A || !B))
|
|
|
|
return true;
|
2014-03-20 03:12:01 +01:00
|
|
|
}
|
2010-11-15 17:33:49 +01:00
|
|
|
}
|
2009-10-16 03:33:57 +02:00
|
|
|
|
2014-04-13 06:57:38 +02:00
|
|
|
Res = MCValue::get(SRE, nullptr, 0);
|
2009-06-29 22:40:36 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Unary: {
|
2009-08-31 10:06:59 +02:00
|
|
|
const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this);
|
2009-06-30 03:49:52 +02:00
|
|
|
MCValue Value;
|
2009-06-29 22:40:36 +02:00
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Value, Asm, Layout, Fixup,
|
2015-03-25 14:16:53 +01:00
|
|
|
Addrs, InSet))
|
2009-06-29 22:40:36 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (AUE->getOpcode()) {
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCUnaryExpr::LNot:
|
2009-07-01 08:48:00 +02:00
|
|
|
if (!Value.isAbsolute())
|
2009-06-30 03:49:52 +02:00
|
|
|
return false;
|
|
|
|
Res = MCValue::get(!Value.getConstant());
|
|
|
|
break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCUnaryExpr::Minus:
|
2009-06-30 03:49:52 +02:00
|
|
|
/// -(a - b + const) ==> (b - a - const)
|
2009-08-11 19:47:52 +02:00
|
|
|
if (Value.getSymA() && !Value.getSymB())
|
2009-06-30 03:49:52 +02:00
|
|
|
return false;
|
2016-05-20 16:09:41 +02:00
|
|
|
|
|
|
|
// The cast avoids undefined behavior if the constant is INT64_MIN.
|
2010-03-18 01:59:10 +01:00
|
|
|
Res = MCValue::get(Value.getSymB(), Value.getSymA(),
|
2016-05-20 16:09:41 +02:00
|
|
|
-(uint64_t)Value.getConstant());
|
2009-06-30 03:49:52 +02:00
|
|
|
break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCUnaryExpr::Not:
|
2009-07-01 08:48:00 +02:00
|
|
|
if (!Value.isAbsolute())
|
2009-06-30 03:49:52 +02:00
|
|
|
return false;
|
2010-03-18 01:59:10 +01:00
|
|
|
Res = MCValue::get(~Value.getConstant());
|
2009-06-30 03:49:52 +02:00
|
|
|
break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCUnaryExpr::Plus:
|
2009-06-30 03:49:52 +02:00
|
|
|
Res = Value;
|
|
|
|
break;
|
2009-06-29 22:40:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Binary: {
|
2009-08-31 10:06:59 +02:00
|
|
|
const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this);
|
2009-06-30 03:49:52 +02:00
|
|
|
MCValue LHSValue, RHSValue;
|
2010-03-18 01:59:10 +01:00
|
|
|
|
2015-05-30 03:25:56 +02:00
|
|
|
if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, Layout, Fixup,
|
2015-03-25 14:16:53 +01:00
|
|
|
Addrs, InSet) ||
|
2015-05-30 03:25:56 +02:00
|
|
|
!ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, Layout, Fixup,
|
2018-08-16 18:31:14 +02:00
|
|
|
Addrs, InSet)) {
|
|
|
|
// Check if both are Target Expressions, see if we can compare them.
|
|
|
|
if (const MCTargetExpr *L = dyn_cast<MCTargetExpr>(ABE->getLHS()))
|
|
|
|
if (const MCTargetExpr *R = cast<MCTargetExpr>(ABE->getRHS())) {
|
|
|
|
switch (ABE->getOpcode()) {
|
|
|
|
case MCBinaryExpr::EQ:
|
|
|
|
Res = MCValue::get((L->isEqualTo(R)) ? -1 : 0);
|
|
|
|
return true;
|
|
|
|
case MCBinaryExpr::NE:
|
|
|
|
Res = MCValue::get((R->isEqualTo(R)) ? 0 : -1);
|
|
|
|
return true;
|
2018-08-16 19:22:31 +02:00
|
|
|
default: break;
|
2018-08-16 18:31:14 +02:00
|
|
|
}
|
|
|
|
}
|
2009-06-29 22:40:36 +02:00
|
|
|
return false;
|
2018-08-16 18:31:14 +02:00
|
|
|
}
|
2009-06-29 22:40:36 +02:00
|
|
|
|
2009-06-30 03:49:52 +02:00
|
|
|
// We only support a few operations on non-constant expressions, handle
|
|
|
|
// those first.
|
2009-07-01 08:48:00 +02:00
|
|
|
if (!LHSValue.isAbsolute() || !RHSValue.isAbsolute()) {
|
2009-06-30 03:49:52 +02:00
|
|
|
switch (ABE->getOpcode()) {
|
|
|
|
default:
|
|
|
|
return false;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCBinaryExpr::Sub:
|
2009-06-30 04:08:27 +02:00
|
|
|
// Negate RHS and add.
|
2016-05-20 16:09:41 +02:00
|
|
|
// The cast avoids undefined behavior if the constant is INT64_MIN.
|
2010-12-18 04:57:21 +01:00
|
|
|
return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue,
|
2009-06-30 04:08:27 +02:00
|
|
|
RHSValue.getSymB(), RHSValue.getSymA(),
|
2016-05-20 16:09:41 +02:00
|
|
|
-(uint64_t)RHSValue.getConstant(), Res);
|
2009-06-30 04:08:27 +02:00
|
|
|
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCBinaryExpr::Add:
|
2010-12-18 04:57:21 +01:00
|
|
|
return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue,
|
2009-06-30 04:08:27 +02:00
|
|
|
RHSValue.getSymA(), RHSValue.getSymB(),
|
2015-03-25 20:24:39 +01:00
|
|
|
RHSValue.getConstant(), Res);
|
2009-06-30 03:49:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-29 22:40:36 +02:00
|
|
|
// FIXME: We need target hooks for the evaluation. It may be limited in
|
2015-04-28 02:21:32 +02:00
|
|
|
// width, and gas defines the result of comparisons differently from
|
|
|
|
// Apple as.
|
2009-06-30 18:02:47 +02:00
|
|
|
int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant();
|
|
|
|
int64_t Result = 0;
|
2018-05-14 07:25:36 +02:00
|
|
|
auto Op = ABE->getOpcode();
|
|
|
|
switch (Op) {
|
2015-04-28 02:21:32 +02:00
|
|
|
case MCBinaryExpr::AShr: Result = LHS >> RHS; break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCBinaryExpr::Add: Result = LHS + RHS; break;
|
|
|
|
case MCBinaryExpr::And: Result = LHS & RHS; break;
|
2015-09-12 00:04:21 +02:00
|
|
|
case MCBinaryExpr::Div:
|
2018-02-22 19:06:48 +01:00
|
|
|
case MCBinaryExpr::Mod:
|
2015-09-11 22:47:35 +02:00
|
|
|
// Handle division by zero. gas just emits a warning and keeps going,
|
|
|
|
// we try to be stricter.
|
|
|
|
// FIXME: Currently the caller of this function has no way to understand
|
|
|
|
// we're bailing out because of 'division by zero'. Therefore, it will
|
|
|
|
// emit a 'expected relocatable expression' error. It would be nice to
|
|
|
|
// change this code to emit a better diagnostic.
|
|
|
|
if (RHS == 0)
|
|
|
|
return false;
|
2018-02-22 19:06:48 +01:00
|
|
|
if (ABE->getOpcode() == MCBinaryExpr::Div)
|
|
|
|
Result = LHS / RHS;
|
|
|
|
else
|
|
|
|
Result = LHS % RHS;
|
2015-09-12 00:04:21 +02:00
|
|
|
break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCBinaryExpr::EQ: Result = LHS == RHS; break;
|
|
|
|
case MCBinaryExpr::GT: Result = LHS > RHS; break;
|
|
|
|
case MCBinaryExpr::GTE: Result = LHS >= RHS; break;
|
|
|
|
case MCBinaryExpr::LAnd: Result = LHS && RHS; break;
|
|
|
|
case MCBinaryExpr::LOr: Result = LHS || RHS; break;
|
2015-04-28 02:21:32 +02:00
|
|
|
case MCBinaryExpr::LShr: Result = uint64_t(LHS) >> uint64_t(RHS); break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCBinaryExpr::LT: Result = LHS < RHS; break;
|
|
|
|
case MCBinaryExpr::LTE: Result = LHS <= RHS; break;
|
|
|
|
case MCBinaryExpr::Mul: Result = LHS * RHS; break;
|
|
|
|
case MCBinaryExpr::NE: Result = LHS != RHS; break;
|
|
|
|
case MCBinaryExpr::Or: Result = LHS | RHS; break;
|
2020-07-31 08:24:09 +02:00
|
|
|
case MCBinaryExpr::OrNot: Result = LHS | ~RHS; break;
|
2015-06-23 09:32:55 +02:00
|
|
|
case MCBinaryExpr::Shl: Result = uint64_t(LHS) << uint64_t(RHS); break;
|
2009-08-31 10:06:59 +02:00
|
|
|
case MCBinaryExpr::Sub: Result = LHS - RHS; break;
|
|
|
|
case MCBinaryExpr::Xor: Result = LHS ^ RHS; break;
|
2009-06-29 22:40:36 +02:00
|
|
|
}
|
|
|
|
|
2018-05-14 07:25:36 +02:00
|
|
|
switch (Op) {
|
|
|
|
default:
|
|
|
|
Res = MCValue::get(Result);
|
|
|
|
break;
|
|
|
|
case MCBinaryExpr::EQ:
|
|
|
|
case MCBinaryExpr::GT:
|
|
|
|
case MCBinaryExpr::GTE:
|
|
|
|
case MCBinaryExpr::LT:
|
|
|
|
case MCBinaryExpr::LTE:
|
|
|
|
case MCBinaryExpr::NE:
|
|
|
|
// A comparison operator returns a -1 if true and 0 if false.
|
|
|
|
Res = MCValue::get(Result ? -1 : 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-06-29 22:40:36 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-07 06:05:23 +01:00
|
|
|
llvm_unreachable("Invalid assembly expression kind!");
|
2009-08-31 10:07:22 +02:00
|
|
|
}
|
2011-04-29 20:00:03 +02:00
|
|
|
|
2015-10-05 14:07:05 +02:00
|
|
|
MCFragment *MCExpr::findAssociatedFragment() const {
|
2011-04-29 20:00:03 +02:00
|
|
|
switch (getKind()) {
|
|
|
|
case Target:
|
|
|
|
// We never look through target specific expressions.
|
2015-10-05 14:07:05 +02:00
|
|
|
return cast<MCTargetExpr>(this)->findAssociatedFragment();
|
2011-04-29 20:00:03 +02:00
|
|
|
|
|
|
|
case Constant:
|
2015-10-05 14:07:05 +02:00
|
|
|
return MCSymbol::AbsolutePseudoFragment;
|
2011-04-29 20:00:03 +02:00
|
|
|
|
|
|
|
case SymbolRef: {
|
|
|
|
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
|
|
|
|
const MCSymbol &Sym = SRE->getSymbol();
|
2015-10-05 14:07:05 +02:00
|
|
|
return Sym.getFragment();
|
2011-04-29 20:00:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case Unary:
|
2015-10-05 14:07:05 +02:00
|
|
|
return cast<MCUnaryExpr>(this)->getSubExpr()->findAssociatedFragment();
|
2011-04-29 20:00:03 +02:00
|
|
|
|
|
|
|
case Binary: {
|
|
|
|
const MCBinaryExpr *BE = cast<MCBinaryExpr>(this);
|
2015-10-05 14:07:05 +02:00
|
|
|
MCFragment *LHS_F = BE->getLHS()->findAssociatedFragment();
|
|
|
|
MCFragment *RHS_F = BE->getRHS()->findAssociatedFragment();
|
2011-04-29 20:00:03 +02:00
|
|
|
|
2015-10-05 14:07:05 +02:00
|
|
|
// If either is absolute, return the other.
|
|
|
|
if (LHS_F == MCSymbol::AbsolutePseudoFragment)
|
|
|
|
return RHS_F;
|
|
|
|
if (RHS_F == MCSymbol::AbsolutePseudoFragment)
|
|
|
|
return LHS_F;
|
2011-04-29 20:00:03 +02:00
|
|
|
|
MC: For variable symbols, maintain MCSymbol::Section as a cache.
Fixes PR19582.
Previously, when an asm assignment (.set or =) was created, we would look up
the section immediately in MCSymbol::setVariableValue. This caused symbols
to receive the wrong section if the RHS of the assignment had not been seen
yet. This had a knock-on effect in the object file emitters, causing them
to emit extra symbols, or to give symbols the wrong visibility or the wrong
section. For example, in the following asm:
.data
.Llocal:
.text
leaq .Llocal1(%rip), %rdi
.Llocal1 = .Llocal2
.Llocal2 = .Llocal
the first assignment would give .Llocal1 a null section, which would never get
fixed up by the second assignment. This would cause the ELF object file emitter
to consider .Llocal1 to be an undefined symbol and give it external linkage,
even though .Llocal1 should not have been emitted at all in the object file.
Or in the following asm:
alias_to_local = Ltmp0
Ltmp0:
the Mach-O object file emitter would give the alias_to_local symbol a n_type
of N_SECT and a n_sect of 0. This is invalid under the Mach-O specification,
which requires N_SECT symbols to receive a non-zero section number if the
symbol is defined in a section in the object file.
https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/MachORuntime/#//apple_ref/c/tag/nlist
After this change we do not look up the section when the assignment is created,
but instead look it up on demand and store it in Section, which is treated
as a cache if the symbol is a variable symbol.
This change also fixes a bug in MCExpr::FindAssociatedSection. Previously,
if we saw a subtraction, we would return the first referenced section, even in
cases where we should have been returning the absolute pseudo-section. Now we
always return the absolute pseudo-section for expressions that subtract two
section-derived expressions. This isn't always correct (e.g. if one of the
sections ends up being laid out at an absolute address), but it's probably
the best we can do without more context.
This allows us to remove code in two places where we appear to have been
working around this bug, in MachObjectWriter::markAbsoluteVariableSymbols
and in X86AsmPrinter::EmitStartOfAsmFile.
Re-applies r233595 (aka D8586), which was reverted in r233898.
Differential Revision: http://reviews.llvm.org/D8798
llvm-svn: 233995
2015-04-03 03:46:11 +02:00
|
|
|
// Not always correct, but probably the best we can do without more context.
|
|
|
|
if (BE->getOpcode() == MCBinaryExpr::Sub)
|
2015-10-05 14:07:05 +02:00
|
|
|
return MCSymbol::AbsolutePseudoFragment;
|
MC: For variable symbols, maintain MCSymbol::Section as a cache.
Fixes PR19582.
Previously, when an asm assignment (.set or =) was created, we would look up
the section immediately in MCSymbol::setVariableValue. This caused symbols
to receive the wrong section if the RHS of the assignment had not been seen
yet. This had a knock-on effect in the object file emitters, causing them
to emit extra symbols, or to give symbols the wrong visibility or the wrong
section. For example, in the following asm:
.data
.Llocal:
.text
leaq .Llocal1(%rip), %rdi
.Llocal1 = .Llocal2
.Llocal2 = .Llocal
the first assignment would give .Llocal1 a null section, which would never get
fixed up by the second assignment. This would cause the ELF object file emitter
to consider .Llocal1 to be an undefined symbol and give it external linkage,
even though .Llocal1 should not have been emitted at all in the object file.
Or in the following asm:
alias_to_local = Ltmp0
Ltmp0:
the Mach-O object file emitter would give the alias_to_local symbol a n_type
of N_SECT and a n_sect of 0. This is invalid under the Mach-O specification,
which requires N_SECT symbols to receive a non-zero section number if the
symbol is defined in a section in the object file.
https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/MachORuntime/#//apple_ref/c/tag/nlist
After this change we do not look up the section when the assignment is created,
but instead look it up on demand and store it in Section, which is treated
as a cache if the symbol is a variable symbol.
This change also fixes a bug in MCExpr::FindAssociatedSection. Previously,
if we saw a subtraction, we would return the first referenced section, even in
cases where we should have been returning the absolute pseudo-section. Now we
always return the absolute pseudo-section for expressions that subtract two
section-derived expressions. This isn't always correct (e.g. if one of the
sections ends up being laid out at an absolute address), but it's probably
the best we can do without more context.
This allows us to remove code in two places where we appear to have been
working around this bug, in MachObjectWriter::markAbsoluteVariableSymbols
and in X86AsmPrinter::EmitStartOfAsmFile.
Re-applies r233595 (aka D8586), which was reverted in r233898.
Differential Revision: http://reviews.llvm.org/D8798
llvm-svn: 233995
2015-04-03 03:46:11 +02:00
|
|
|
|
2015-10-05 14:07:05 +02:00
|
|
|
// Otherwise, return the first non-null fragment.
|
|
|
|
return LHS_F ? LHS_F : RHS_F;
|
2011-04-29 20:00:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-07 06:05:23 +01:00
|
|
|
llvm_unreachable("Invalid assembly expression kind!");
|
2011-04-29 20:00:03 +02:00
|
|
|
}
|