forked from OSchip/llvm-project
[WebAssembly] Add explict TLS symbol flag
As before we maintain backwards compat with older object files by also infering the TLS flag based on the name of the segment. This change is was split out from https://reviews.llvm.org/D108877. Differential Revision: https://reviews.llvm.org/D109426
This commit is contained in:
parent
3765d284c4
commit
44177e5fb2
|
@ -81,12 +81,7 @@ public:
|
|||
void writeRelocations(llvm::raw_ostream &os) const;
|
||||
void generateRelocationCode(raw_ostream &os) const;
|
||||
|
||||
bool isTLS() const {
|
||||
// Older object files don't include WASM_SEG_FLAG_TLS and instead
|
||||
// relied on the naming convention.
|
||||
return flags & llvm::wasm::WASM_SEG_FLAG_TLS || name.startswith(".tdata") ||
|
||||
name.startswith(".tbss");
|
||||
}
|
||||
bool isTLS() const { return flags & llvm::wasm::WASM_SEG_FLAG_TLS; }
|
||||
|
||||
ObjFile *file;
|
||||
OutputSection *outputSec = nullptr;
|
||||
|
@ -113,11 +108,15 @@ public:
|
|||
// Signals the chunk was discarded by COMDAT handling.
|
||||
unsigned discarded : 1;
|
||||
|
||||
// Signals that the chuck was implicitly marked as TLS based on its name
|
||||
// alone. This is a compatibility mechanism to support older object files.
|
||||
unsigned implicitTLS : 1;
|
||||
|
||||
protected:
|
||||
InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0,
|
||||
uint32_t flags = 0)
|
||||
: name(name), file(f), alignment(alignment), flags(flags), sectionKind(k),
|
||||
live(!config->gcSections), discarded(false) {}
|
||||
live(!config->gcSections), discarded(false), implicitTLS(false) {}
|
||||
ArrayRef<uint8_t> data() const { return rawData; }
|
||||
uint64_t getTombstone() const;
|
||||
|
||||
|
|
|
@ -491,7 +491,14 @@ void ObjFile::parse(bool ignoreComdats) {
|
|||
} else
|
||||
seg = make<InputSegment>(s, this);
|
||||
seg->discarded = isExcludedByComdat(seg);
|
||||
|
||||
// Older object files did not include WASM_SEG_FLAG_TLS and instead
|
||||
// relied on the naming convention. To maintain compat with such objects
|
||||
// we still imply the TLS flag based on the name of the segment.
|
||||
if (!seg->isTLS() &&
|
||||
(seg->name.startswith(".tdata") || seg->name.startswith(".tbss"))) {
|
||||
seg->flags |= WASM_SEG_FLAG_TLS;
|
||||
seg->implicitTLS = true;
|
||||
}
|
||||
segments.emplace_back(seg);
|
||||
}
|
||||
setRelocs(segments, dataSection);
|
||||
|
@ -592,6 +599,9 @@ Symbol *ObjFile::createDefined(const WasmSymbol &sym) {
|
|||
InputChunk *seg = segments[sym.Info.DataRef.Segment];
|
||||
auto offset = sym.Info.DataRef.Offset;
|
||||
auto size = sym.Info.DataRef.Size;
|
||||
if (seg->implicitTLS) {
|
||||
flags |= WASM_SYMBOL_TLS;
|
||||
}
|
||||
if (sym.isBindingLocal())
|
||||
return make<DefinedData>(name, flags, this, seg, offset, size);
|
||||
if (seg->discarded)
|
||||
|
|
|
@ -120,6 +120,12 @@ void scanRelocations(InputChunk *chunk) {
|
|||
// merged with normal data and allowing TLS relocation in non-TLS
|
||||
// segments.
|
||||
if (config->sharedMemory) {
|
||||
if (!sym->isTLS()) {
|
||||
error(toString(file) + ": relocation " +
|
||||
relocTypeToString(reloc.Type) +
|
||||
" cannot be used against non-TLS symbol `" + toString(*sym) +
|
||||
"`");
|
||||
}
|
||||
if (auto *D = dyn_cast<DefinedData>(sym)) {
|
||||
if (!D->segment->outputSeg->isTLS()) {
|
||||
error(toString(file) + ": relocation " +
|
||||
|
@ -133,6 +139,12 @@ void scanRelocations(InputChunk *chunk) {
|
|||
}
|
||||
|
||||
if (config->isPic) {
|
||||
if (sym->isTLS() && sym->isUndefined()) {
|
||||
error(toString(file) +
|
||||
": TLS symbol is undefined, but TLS symbols cannot yet be "
|
||||
"imported: `" +
|
||||
toString(*sym) + "`");
|
||||
}
|
||||
switch (reloc.Type) {
|
||||
case R_WASM_TABLE_INDEX_SLEB:
|
||||
case R_WASM_TABLE_INDEX_SLEB64:
|
||||
|
@ -146,15 +158,6 @@ void scanRelocations(InputChunk *chunk) {
|
|||
" cannot be used against symbol " + toString(*sym) +
|
||||
"; recompile with -fPIC");
|
||||
break;
|
||||
case R_WASM_MEMORY_ADDR_TLS_SLEB:
|
||||
case R_WASM_MEMORY_ADDR_TLS_SLEB64:
|
||||
if (!sym->isDefined()) {
|
||||
error(toString(file) +
|
||||
": TLS symbol is undefined, but TLS symbols cannot yet be "
|
||||
"imported: `" +
|
||||
toString(*sym) + "`");
|
||||
}
|
||||
break;
|
||||
case R_WASM_TABLE_INDEX_I32:
|
||||
case R_WASM_TABLE_INDEX_I64:
|
||||
case R_WASM_MEMORY_ADDR_I32:
|
||||
|
|
|
@ -205,6 +205,8 @@ bool Symbol::isHidden() const {
|
|||
return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
|
||||
}
|
||||
|
||||
bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }
|
||||
|
||||
void Symbol::setHidden(bool isHidden) {
|
||||
LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
|
||||
flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
bool isLocal() const;
|
||||
bool isWeak() const;
|
||||
bool isHidden() const;
|
||||
bool isTLS() const;
|
||||
|
||||
// Returns true if this symbol exists in a discarded (due to COMDAT) section
|
||||
bool isDiscarded() const;
|
||||
|
|
|
@ -639,7 +639,7 @@ void Writer::calculateExports() {
|
|||
} else if (auto *t = dyn_cast<DefinedTag>(sym)) {
|
||||
export_ = {name, WASM_EXTERNAL_TAG, t->getTagIndex()};
|
||||
} else if (auto *d = dyn_cast<DefinedData>(sym)) {
|
||||
if (d->segment && d->segment->isTLS()) {
|
||||
if (sym->isTLS()) {
|
||||
// We can't currenly export TLS data symbols.
|
||||
if (sym->isExportedExplicit())
|
||||
error("TLS symbols cannot yet be exported: `" + toString(*sym) + "`");
|
||||
|
|
|
@ -379,6 +379,7 @@ const unsigned WASM_SYMBOL_UNDEFINED = 0x10;
|
|||
const unsigned WASM_SYMBOL_EXPORTED = 0x20;
|
||||
const unsigned WASM_SYMBOL_EXPLICIT_NAME = 0x40;
|
||||
const unsigned WASM_SYMBOL_NO_STRIP = 0x80;
|
||||
const unsigned WASM_SYMBOL_TLS = 0x100;
|
||||
|
||||
#define WASM_RELOC(name, value) name = value,
|
||||
|
||||
|
|
|
@ -67,6 +67,11 @@ public:
|
|||
modifyFlags(wasm::WASM_SYMBOL_NO_STRIP, wasm::WASM_SYMBOL_NO_STRIP);
|
||||
}
|
||||
|
||||
bool isTLS() const { return getFlags() & wasm::WASM_SYMBOL_TLS; }
|
||||
void setTLS() const {
|
||||
modifyFlags(wasm::WASM_SYMBOL_TLS, wasm::WASM_SYMBOL_TLS);
|
||||
}
|
||||
|
||||
bool isWeak() const { return IsWeak; }
|
||||
void setWeak(bool isWeak) { IsWeak = isWeak; }
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
/// @{
|
||||
|
||||
void changeSection(MCSection *Section, const MCExpr *Subsection) override;
|
||||
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
|
||||
void emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc, MCFragment *F,
|
||||
uint64_t Offset) override;
|
||||
void emitAssemblerFlag(MCAssemblerFlag Flag) override;
|
||||
void emitThumbFunc(MCSymbol *Func) override;
|
||||
void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
|
||||
|
@ -68,6 +71,8 @@ private:
|
|||
void emitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &) override;
|
||||
void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
|
||||
|
||||
void fixSymbolsInTLSFixups(const MCExpr *expr);
|
||||
|
||||
/// Merge the content of the fragment \p EF into the fragment \p DF.
|
||||
void mergeFragment(MCDataFragment *, MCDataFragment *);
|
||||
|
||||
|
|
|
@ -49,6 +49,27 @@ void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) {
|
|||
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
||||
}
|
||||
|
||||
void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
|
||||
auto *Symbol = cast<MCSymbolWasm>(S);
|
||||
MCObjectStreamer::emitLabel(Symbol, Loc);
|
||||
|
||||
const MCSectionWasm &Section =
|
||||
static_cast<const MCSectionWasm &>(*getCurrentSectionOnly());
|
||||
if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS)
|
||||
Symbol->setTLS();
|
||||
}
|
||||
|
||||
void MCWasmStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment *F,
|
||||
uint64_t Offset) {
|
||||
auto *Symbol = cast<MCSymbolWasm>(S);
|
||||
MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset);
|
||||
|
||||
const MCSectionWasm &Section =
|
||||
static_cast<const MCSectionWasm &>(*getCurrentSectionOnly());
|
||||
if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS)
|
||||
Symbol->setTLS();
|
||||
}
|
||||
|
||||
void MCWasmStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) {
|
||||
// Let the target do whatever target specific stuff it needs to do.
|
||||
getAssembler().getBackend().handleAssemblerFlag(Flag);
|
||||
|
@ -117,6 +138,10 @@ bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
|
|||
Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
|
||||
break;
|
||||
|
||||
case MCSA_ELF_TypeTLS:
|
||||
Symbol->setTLS();
|
||||
break;
|
||||
|
||||
case MCSA_ELF_TypeObject:
|
||||
case MCSA_Cold:
|
||||
break;
|
||||
|
@ -156,6 +181,10 @@ void MCWasmStreamer::emitIdent(StringRef IdentString) {
|
|||
void MCWasmStreamer::emitInstToFragment(const MCInst &Inst,
|
||||
const MCSubtargetInfo &STI) {
|
||||
this->MCObjectStreamer::emitInstToFragment(Inst, STI);
|
||||
MCRelaxableFragment &F = *cast<MCRelaxableFragment>(getCurrentFragment());
|
||||
|
||||
for (auto &Fixup : F.getFixups())
|
||||
fixSymbolsInTLSFixups(Fixup.getValue());
|
||||
}
|
||||
|
||||
void MCWasmStreamer::emitInstToData(const MCInst &Inst,
|
||||
|
@ -166,6 +195,9 @@ void MCWasmStreamer::emitInstToData(const MCInst &Inst,
|
|||
raw_svector_ostream VecOS(Code);
|
||||
Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
|
||||
|
||||
for (auto &Fixup : Fixups)
|
||||
fixSymbolsInTLSFixups(Fixup.getValue());
|
||||
|
||||
// Append the encoded instruction to the current data fragment (or create a
|
||||
// new such fragment if the current fragment is not a data fragment).
|
||||
MCDataFragment *DF = getOrCreateDataFragment();
|
||||
|
@ -185,16 +217,32 @@ void MCWasmStreamer::finishImpl() {
|
|||
this->MCObjectStreamer::finishImpl();
|
||||
}
|
||||
|
||||
MCStreamer *llvm::createWasmStreamer(MCContext &Context,
|
||||
std::unique_ptr<MCAsmBackend> &&MAB,
|
||||
std::unique_ptr<MCObjectWriter> &&OW,
|
||||
std::unique_ptr<MCCodeEmitter> &&CE,
|
||||
bool RelaxAll) {
|
||||
MCWasmStreamer *S =
|
||||
new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
|
||||
if (RelaxAll)
|
||||
S->getAssembler().setRelaxAll(true);
|
||||
return S;
|
||||
void MCWasmStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) {
|
||||
switch (expr->getKind()) {
|
||||
case MCExpr::Target:
|
||||
case MCExpr::Constant:
|
||||
break;
|
||||
|
||||
case MCExpr::Binary: {
|
||||
const MCBinaryExpr *be = cast<MCBinaryExpr>(expr);
|
||||
fixSymbolsInTLSFixups(be->getLHS());
|
||||
fixSymbolsInTLSFixups(be->getRHS());
|
||||
break;
|
||||
}
|
||||
|
||||
case MCExpr::SymbolRef: {
|
||||
const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(expr);
|
||||
if (symRef.getKind() == MCSymbolRefExpr::VK_WASM_TLSREL) {
|
||||
getAssembler().registerSymbol(symRef.getSymbol());
|
||||
cast<MCSymbolWasm>(symRef.getSymbol()).setTLS();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MCExpr::Unary:
|
||||
fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MCWasmStreamer::emitThumbFunc(MCSymbol *Func) {
|
||||
|
@ -215,3 +263,15 @@ void MCWasmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
|
|||
uint64_t Size, unsigned ByteAlignment) {
|
||||
llvm_unreachable("Wasm doesn't support this directive");
|
||||
}
|
||||
|
||||
MCStreamer *llvm::createWasmStreamer(MCContext &Context,
|
||||
std::unique_ptr<MCAsmBackend> &&MAB,
|
||||
std::unique_ptr<MCObjectWriter> &&OW,
|
||||
std::unique_ptr<MCCodeEmitter> &&CE,
|
||||
bool RelaxAll) {
|
||||
MCWasmStreamer *S =
|
||||
new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
|
||||
if (RelaxAll)
|
||||
S->getAssembler().setRelaxAll(true);
|
||||
return S;
|
||||
}
|
||||
|
|
|
@ -1748,6 +1748,8 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
|
|||
Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
|
||||
if (WS.hasExportName())
|
||||
Flags |= wasm::WASM_SYMBOL_EXPORTED;
|
||||
if (WS.isTLS())
|
||||
Flags |= wasm::WASM_SYMBOL_TLS;
|
||||
|
||||
wasm::WasmSymbolInfo Info;
|
||||
Info.Name = WS.getName();
|
||||
|
|
|
@ -561,6 +561,7 @@ void ScalarBitSetTraits<WasmYAML::SymbolFlags>::bitset(
|
|||
BCaseMask(EXPORTED, EXPORTED);
|
||||
BCaseMask(EXPLICIT_NAME, EXPLICIT_NAME);
|
||||
BCaseMask(NO_STRIP, NO_STRIP);
|
||||
BCaseMask(TLS, TLS);
|
||||
#undef BCaseMask
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ tls_store:
|
|||
i32.store 0
|
||||
end_function
|
||||
|
||||
tls_get_undefined:
|
||||
.functype tls_get_undefined (i32) -> (i32)
|
||||
i32.const tls_undefined@TLSREL
|
||||
end_function
|
||||
|
||||
.section .tls.foo,"T",@
|
||||
# CHECK: .tls.foo,"T",@
|
||||
tls1:
|
||||
|
@ -56,13 +61,22 @@ tls2:
|
|||
# CHECK-OBJ-NEXT: - Index: 2
|
||||
# CHECK-OBJ-NEXT: Kind: DATA
|
||||
# CHECK-OBJ-NEXT: Name: tls1
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL ]
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL, TLS ]
|
||||
# CHECK-OBJ-NEXT: Segment: 0
|
||||
# CHECK-OBJ-NEXT: Size: 4
|
||||
# CHECK-OBJ-NEXT: - Index: 3
|
||||
# CHECK-OBJ-NEXT: Kind: FUNCTION
|
||||
# CHECK-OBJ-NEXT: Name: tls_get_undefined
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL ]
|
||||
# CHECK-OBJ-NEXT: Function: 1
|
||||
# CHECK-OBJ-NEXT: - Index: 4
|
||||
# CHECK-OBJ-NEXT: Kind: DATA
|
||||
# CHECK-OBJ-NEXT: Name: tls_undefined
|
||||
# CHECK-OBJ-NEXT: Flags: [ UNDEFINED, TLS ]
|
||||
# CHECK-OBJ-NEXT: - Index: 5
|
||||
# CHECK-OBJ-NEXT: Kind: DATA
|
||||
# CHECK-OBJ-NEXT: Name: tls2
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL ]
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL, TLS ]
|
||||
# CHECK-OBJ-NEXT: Segment: 1
|
||||
# CHECK-OBJ-NEXT: Size: 4
|
||||
# CHECK-OBJ-NEXT: SegmentInfo:
|
||||
|
|
|
@ -56,13 +56,13 @@ tls2:
|
|||
# CHECK-OBJ-NEXT: - Index: 2
|
||||
# CHECK-OBJ-NEXT: Kind: DATA
|
||||
# CHECK-OBJ-NEXT: Name: tls1
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL ]
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL, TLS ]
|
||||
# CHECK-OBJ-NEXT: Segment: 0
|
||||
# CHECK-OBJ-NEXT: Size: 4
|
||||
# CHECK-OBJ-NEXT: - Index: 3
|
||||
# CHECK-OBJ-NEXT: Kind: DATA
|
||||
# CHECK-OBJ-NEXT: Name: tls2
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL ]
|
||||
# CHECK-OBJ-NEXT: Flags: [ BINDING_LOCAL, TLS ]
|
||||
# CHECK-OBJ-NEXT: Segment: 1
|
||||
# CHECK-OBJ-NEXT: Size: 4
|
||||
# CHECK-OBJ-NEXT: SegmentInfo:
|
||||
|
|
Loading…
Reference in New Issue