[Coding style change][lld] Rename variables for non-ELF ports

This patch does the same thing as r365595 to other subdirectories,
which completes the naming style change for the entire lld directory.

With this, the naming style conversion is complete for lld.

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

llvm-svn: 365730
This commit is contained in:
Rui Ueyama 2019-07-11 05:40:30 +00:00
parent 51f5079191
commit 136d27ab4d
88 changed files with 9345 additions and 9345 deletions

File diff suppressed because it is too large Load Diff

View File

@ -40,10 +40,10 @@ class RuntimePseudoReloc;
class Symbol;
// Mask for permissions (discardable, writable, readable, executable, etc).
const uint32_t PermMask = 0xFE000000;
const uint32_t permMask = 0xFE000000;
// Mask for section types (code, data, bss).
const uint32_t TypeMask = 0x000000E0;
const uint32_t typeMask = 0x000000E0;
// The log base 2 of the largest section alignment, which is log2(8192), or 13.
enum : unsigned { Log2MaxSectionAlignment = 13 };
@ -55,23 +55,23 @@ enum : unsigned { Log2MaxSectionAlignment = 13 };
class Chunk {
public:
enum Kind : uint8_t { SectionKind, OtherKind, ImportThunkKind };
Kind kind() const { return ChunkKind; }
Kind kind() const { return chunkKind; }
// Returns the size of this chunk (even if this is a common or BSS.)
size_t getSize() const;
// Returns chunk alignment in power of two form. Value values are powers of
// two from 1 to 8192.
uint32_t getAlignment() const { return 1U << P2Align; }
uint32_t getAlignment() const { return 1U << p2Align; }
// Update the chunk section alignment measured in bytes. Internally alignment
// is stored in log2.
void setAlignment(uint32_t Align) {
void setAlignment(uint32_t align) {
// Treat zero byte alignment as 1 byte alignment.
Align = Align ? Align : 1;
assert(llvm::isPowerOf2_32(Align) && "alignment is not a power of 2");
P2Align = llvm::Log2_32(Align);
assert(P2Align <= Log2MaxSectionAlignment &&
align = align ? align : 1;
assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2");
p2Align = llvm::Log2_32(align);
assert(p2Align <= Log2MaxSectionAlignment &&
"impossible requested alignment");
}
@ -79,15 +79,15 @@ public:
// beginning of the file. Because this function may use RVA values
// of other chunks for relocations, you need to set them properly
// before calling this function.
void writeTo(uint8_t *Buf) const;
void writeTo(uint8_t *buf) const;
// The writer sets and uses the addresses. In practice, PE images cannot be
// larger than 2GB. Chunks are always laid as part of the image, so Chunk RVAs
// can be stored with 32 bits.
uint32_t getRVA() const { return RVA; }
void setRVA(uint64_t V) {
RVA = (uint32_t)V;
assert(RVA == V && "RVA truncated");
uint32_t getRVA() const { return rva; }
void setRVA(uint64_t v) {
rva = (uint32_t)v;
assert(rva == v && "RVA truncated");
}
// Returns readable/writable/executable bits.
@ -99,13 +99,13 @@ public:
// An output section has pointers to chunks in the section, and each
// chunk has a back pointer to an output section.
void setOutputSectionIdx(uint16_t O) { OSIdx = O; }
uint16_t getOutputSectionIdx() const { return OSIdx; }
void setOutputSectionIdx(uint16_t o) { osidx = o; }
uint16_t getOutputSectionIdx() const { return osidx; }
OutputSection *getOutputSection() const;
// Windows-specific.
// Collect all locations that contain absolute addresses for base relocations.
void getBaserels(std::vector<Baserel> *Res);
void getBaserels(std::vector<Baserel> *res);
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
// bytes, so this is used only for logging or debugging.
@ -117,28 +117,28 @@ public:
bool isHotPatchable() const;
protected:
Chunk(Kind K = OtherKind) : ChunkKind(K), HasData(true), P2Align(0) {}
Chunk(Kind k = OtherKind) : chunkKind(k), hasData(true), p2Align(0) {}
const Kind ChunkKind;
const Kind chunkKind;
public:
// Returns true if this has non-zero data. BSS chunks return
// false. If false is returned, the space occupied by this chunk
// will be filled with zeros. Corresponds to the
// IMAGE_SCN_CNT_UNINITIALIZED_DATA section characteristic bit.
uint8_t HasData : 1;
uint8_t hasData : 1;
public:
// The alignment of this chunk, stored in log2 form. The writer uses the
// value.
uint8_t P2Align : 7;
uint8_t p2Align : 7;
// The output section index for this chunk. The first valid section number is
// one.
uint16_t OSIdx = 0;
uint16_t osidx = 0;
// The RVA of this chunk in the output. The writer sets a value.
uint32_t RVA = 0;
uint32_t rva = 0;
};
class NonSectionChunk : public Chunk {
@ -154,7 +154,7 @@ public:
// beginning of the file. Because this function may use RVA values
// of other chunks for relocations, you need to set them properly
// before calling this function.
virtual void writeTo(uint8_t *Buf) const {}
virtual void writeTo(uint8_t *buf) const {}
// Returns the section name if this is a section chunk.
// It is illegal to call this function on non-section chunks.
@ -164,16 +164,16 @@ public:
// Windows-specific.
// Collect all locations that contain absolute addresses for base relocations.
virtual void getBaserels(std::vector<Baserel> *Res) {}
virtual void getBaserels(std::vector<Baserel> *res) {}
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
// bytes, so this is used only for logging or debugging.
virtual StringRef getDebugName() const { return ""; }
static bool classof(const Chunk *C) { return C->kind() != SectionKind; }
static bool classof(const Chunk *c) { return c->kind() != SectionKind; }
protected:
NonSectionChunk(Kind K = OtherKind) : Chunk(K) {}
NonSectionChunk(Kind k = OtherKind) : Chunk(k) {}
};
// A chunk corresponding a section of an input file.
@ -187,41 +187,41 @@ public:
std::random_access_iterator_tag, Symbol *> {
friend SectionChunk;
ObjFile *File;
ObjFile *file;
symbol_iterator(ObjFile *File, const coff_relocation *I)
: symbol_iterator::iterator_adaptor_base(I), File(File) {}
symbol_iterator(ObjFile *file, const coff_relocation *i)
: symbol_iterator::iterator_adaptor_base(i), file(file) {}
public:
symbol_iterator() = default;
Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); }
Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); }
};
SectionChunk(ObjFile *File, const coff_section *Header);
static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
size_t getSize() const { return Header->SizeOfRawData; }
SectionChunk(ObjFile *file, const coff_section *header);
static bool classof(const Chunk *c) { return c->kind() == SectionKind; }
size_t getSize() const { return header->SizeOfRawData; }
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const;
void writeTo(uint8_t *buf) const;
uint32_t getOutputCharacteristics() const {
return Header->Characteristics & (PermMask | TypeMask);
return header->Characteristics & (permMask | typeMask);
}
StringRef getSectionName() const {
return StringRef(SectionNameData, SectionNameSize);
return StringRef(sectionNameData, sectionNameSize);
}
void getBaserels(std::vector<Baserel> *Res);
void getBaserels(std::vector<Baserel> *res);
bool isCOMDAT() const;
void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
uint64_t P) const;
void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
uint64_t P) const;
void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
uint64_t P) const;
void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
uint64_t P) const;
void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
uint64_t p) const;
void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
uint64_t p) const;
void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
uint64_t p) const;
void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
uint64_t p) const;
void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &Res);
void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);
// Called if the garbage collector decides to not include this chunk
// in a final output. It's supposed to print out a log message to stdout.
@ -229,7 +229,7 @@ public:
// Adds COMDAT associative sections to this COMDAT section. A chunk
// and its children are treated as a group by the garbage collector.
void addAssociative(SectionChunk *Child);
void addAssociative(SectionChunk *child);
StringRef getDebugName() const;
@ -246,19 +246,19 @@ public:
// Allow iteration over the bodies of this chunk's relocated symbols.
llvm::iterator_range<symbol_iterator> symbols() const {
return llvm::make_range(symbol_iterator(File, RelocsData),
symbol_iterator(File, RelocsData + RelocsSize));
return llvm::make_range(symbol_iterator(file, relocsData),
symbol_iterator(file, relocsData + relocsSize));
}
ArrayRef<coff_relocation> getRelocs() const {
return llvm::makeArrayRef(RelocsData, RelocsSize);
return llvm::makeArrayRef(relocsData, relocsSize);
}
// Reloc setter used by ARM range extension thunk insertion.
void setRelocs(ArrayRef<coff_relocation> NewRelocs) {
RelocsData = NewRelocs.data();
RelocsSize = NewRelocs.size();
assert(RelocsSize == NewRelocs.size() && "reloc size truncation");
void setRelocs(ArrayRef<coff_relocation> newRelocs) {
relocsData = newRelocs.data();
relocsSize = newRelocs.size();
assert(relocsSize == newRelocs.size() && "reloc size truncation");
}
// Single linked list iterator for associated comdat children.
@ -267,26 +267,26 @@ public:
AssociatedIterator, std::forward_iterator_tag, SectionChunk> {
public:
AssociatedIterator() = default;
AssociatedIterator(SectionChunk *Head) : Cur(Head) {}
AssociatedIterator &operator=(const AssociatedIterator &R) {
Cur = R.Cur;
AssociatedIterator(SectionChunk *head) : cur(head) {}
AssociatedIterator &operator=(const AssociatedIterator &r) {
cur = r.cur;
return *this;
}
bool operator==(const AssociatedIterator &R) const { return Cur == R.Cur; }
const SectionChunk &operator*() const { return *Cur; }
SectionChunk &operator*() { return *Cur; }
bool operator==(const AssociatedIterator &r) const { return cur == r.cur; }
const SectionChunk &operator*() const { return *cur; }
SectionChunk &operator*() { return *cur; }
AssociatedIterator &operator++() {
Cur = Cur->AssocChildren;
cur = cur->assocChildren;
return *this;
}
private:
SectionChunk *Cur = nullptr;
SectionChunk *cur = nullptr;
};
// Allow iteration over the associated child chunks for this section.
llvm::iterator_range<AssociatedIterator> children() const {
return llvm::make_range(AssociatedIterator(AssocChildren),
return llvm::make_range(AssociatedIterator(assocChildren),
AssociatedIterator(nullptr));
}
@ -295,56 +295,56 @@ public:
ArrayRef<uint8_t> consumeDebugMagic();
static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
StringRef SectionName);
static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> data,
StringRef sectionName);
static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections,
StringRef Name);
static SectionChunk *findByName(ArrayRef<SectionChunk *> sections,
StringRef name);
// The file that this chunk was created from.
ObjFile *File;
ObjFile *file;
// Pointer to the COFF section header in the input file.
const coff_section *Header;
const coff_section *header;
// The COMDAT leader symbol if this is a COMDAT chunk.
DefinedRegular *Sym = nullptr;
DefinedRegular *sym = nullptr;
// The CRC of the contents as described in the COFF spec 4.5.5.
// Auxiliary Format 5: Section Definitions. Used for ICF.
uint32_t Checksum = 0;
uint32_t checksum = 0;
// Used by the garbage collector.
bool Live;
bool live;
// Whether this section needs to be kept distinct from other sections during
// ICF. This is set by the driver using address-significance tables.
bool KeepUnique = false;
bool keepUnique = false;
// The COMDAT selection if this is a COMDAT chunk.
llvm::COFF::COMDATType Selection = (llvm::COFF::COMDATType)0;
llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0;
// A pointer pointing to a replacement for this chunk.
// Initially it points to "this" object. If this chunk is merged
// with other chunk by ICF, it points to another chunk,
// and this chunk is considered as dead.
SectionChunk *Repl;
SectionChunk *repl;
private:
SectionChunk *AssocChildren = nullptr;
SectionChunk *assocChildren = nullptr;
// Used for ICF (Identical COMDAT Folding)
void replace(SectionChunk *Other);
uint32_t Class[2] = {0, 0};
void replace(SectionChunk *other);
uint32_t eqClass[2] = {0, 0};
// Relocations for this section. Size is stored below.
const coff_relocation *RelocsData;
const coff_relocation *relocsData;
// Section name string. Size is stored below.
const char *SectionNameData;
const char *sectionNameData;
uint32_t RelocsSize = 0;
uint32_t SectionNameSize = 0;
uint32_t relocsSize = 0;
uint32_t sectionNameSize = 0;
};
// Inline methods to implement faux-virtual dispatch for SectionChunk.
@ -364,11 +364,11 @@ inline uint32_t Chunk::getOutputCharacteristics() const {
->getOutputCharacteristics();
}
inline void Chunk::writeTo(uint8_t *Buf) const {
inline void Chunk::writeTo(uint8_t *buf) const {
if (isa<SectionChunk>(this))
static_cast<const SectionChunk *>(this)->writeTo(Buf);
static_cast<const SectionChunk *>(this)->writeTo(buf);
else
static_cast<const NonSectionChunk *>(this)->writeTo(Buf);
static_cast<const NonSectionChunk *>(this)->writeTo(buf);
}
inline StringRef Chunk::getSectionName() const {
@ -378,11 +378,11 @@ inline StringRef Chunk::getSectionName() const {
return static_cast<const NonSectionChunk *>(this)->getSectionName();
}
inline void Chunk::getBaserels(std::vector<Baserel> *Res) {
inline void Chunk::getBaserels(std::vector<Baserel> *res) {
if (isa<SectionChunk>(this))
static_cast<SectionChunk *>(this)->getBaserels(Res);
static_cast<SectionChunk *>(this)->getBaserels(res);
else
static_cast<NonSectionChunk *>(this)->getBaserels(Res);
static_cast<NonSectionChunk *>(this)->getBaserels(res);
}
inline StringRef Chunk::getDebugName() const {
@ -403,58 +403,58 @@ inline StringRef Chunk::getDebugName() const {
// on the offsets assigned by the StringTableBuilder.
class MergeChunk : public NonSectionChunk {
public:
MergeChunk(uint32_t Alignment);
static void addSection(SectionChunk *C);
MergeChunk(uint32_t alignment);
static void addSection(SectionChunk *c);
void finalizeContents();
void assignSubsectionRVAs();
uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".rdata"; }
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *buf) const override;
static MergeChunk *Instances[Log2MaxSectionAlignment + 1];
std::vector<SectionChunk *> Sections;
static MergeChunk *instances[Log2MaxSectionAlignment + 1];
std::vector<SectionChunk *> sections;
private:
llvm::StringTableBuilder Builder;
bool Finalized = false;
llvm::StringTableBuilder builder;
bool finalized = false;
};
// A chunk for common symbols. Common chunks don't have actual data.
class CommonChunk : public NonSectionChunk {
public:
CommonChunk(const COFFSymbolRef Sym);
size_t getSize() const override { return Sym.getValue(); }
CommonChunk(const COFFSymbolRef sym);
size_t getSize() const override { return sym.getValue(); }
uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".bss"; }
private:
const COFFSymbolRef Sym;
const COFFSymbolRef sym;
};
// A chunk for linker-created strings.
class StringChunk : public NonSectionChunk {
public:
explicit StringChunk(StringRef S) : Str(S) {}
size_t getSize() const override { return Str.size() + 1; }
void writeTo(uint8_t *Buf) const override;
explicit StringChunk(StringRef s) : str(s) {}
size_t getSize() const override { return str.size() + 1; }
void writeTo(uint8_t *buf) const override;
private:
StringRef Str;
StringRef str;
};
static const uint8_t ImportThunkX86[] = {
static const uint8_t importThunkX86[] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
};
static const uint8_t ImportThunkARM[] = {
static const uint8_t importThunkARM[] = {
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
};
static const uint8_t ImportThunkARM64[] = {
static const uint8_t importThunkARM64[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, #0
0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16]
0x00, 0x02, 0x1f, 0xd6, // br x16
@ -465,83 +465,83 @@ static const uint8_t ImportThunkARM64[] = {
// contents will be a JMP instruction to some __imp_ symbol.
class ImportThunkChunk : public NonSectionChunk {
public:
ImportThunkChunk(Defined *S)
: NonSectionChunk(ImportThunkKind), ImpSymbol(S) {}
static bool classof(const Chunk *C) { return C->kind() == ImportThunkKind; }
ImportThunkChunk(Defined *s)
: NonSectionChunk(ImportThunkKind), impSymbol(s) {}
static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; }
protected:
Defined *ImpSymbol;
Defined *impSymbol;
};
class ImportThunkChunkX64 : public ImportThunkChunk {
public:
explicit ImportThunkChunkX64(Defined *S);
size_t getSize() const override { return sizeof(ImportThunkX86); }
void writeTo(uint8_t *Buf) const override;
explicit ImportThunkChunkX64(Defined *s);
size_t getSize() const override { return sizeof(importThunkX86); }
void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkX86 : public ImportThunkChunk {
public:
explicit ImportThunkChunkX86(Defined *S) : ImportThunkChunk(S) {}
size_t getSize() const override { return sizeof(ImportThunkX86); }
void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) const override;
explicit ImportThunkChunkX86(Defined *s) : ImportThunkChunk(s) {}
size_t getSize() const override { return sizeof(importThunkX86); }
void getBaserels(std::vector<Baserel> *res) override;
void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkARM : public ImportThunkChunk {
public:
explicit ImportThunkChunkARM(Defined *S) : ImportThunkChunk(S) {}
size_t getSize() const override { return sizeof(ImportThunkARM); }
void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) const override;
explicit ImportThunkChunkARM(Defined *s) : ImportThunkChunk(s) {}
size_t getSize() const override { return sizeof(importThunkARM); }
void getBaserels(std::vector<Baserel> *res) override;
void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkARM64 : public ImportThunkChunk {
public:
explicit ImportThunkChunkARM64(Defined *S) : ImportThunkChunk(S) {}
size_t getSize() const override { return sizeof(ImportThunkARM64); }
void writeTo(uint8_t *Buf) const override;
explicit ImportThunkChunkARM64(Defined *s) : ImportThunkChunk(s) {}
size_t getSize() const override { return sizeof(importThunkARM64); }
void writeTo(uint8_t *buf) const override;
};
class RangeExtensionThunkARM : public NonSectionChunk {
public:
explicit RangeExtensionThunkARM(Defined *T) : Target(T) {}
explicit RangeExtensionThunkARM(Defined *t) : target(t) {}
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *buf) const override;
Defined *Target;
Defined *target;
};
class RangeExtensionThunkARM64 : public NonSectionChunk {
public:
explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {}
explicit RangeExtensionThunkARM64(Defined *t) : target(t) {}
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *buf) const override;
Defined *Target;
Defined *target;
};
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public NonSectionChunk {
public:
explicit LocalImportChunk(Defined *S) : Sym(S) {
setAlignment(Config->Wordsize);
explicit LocalImportChunk(Defined *s) : sym(s) {
setAlignment(config->wordsize);
}
size_t getSize() const override;
void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) const override;
void getBaserels(std::vector<Baserel> *res) override;
void writeTo(uint8_t *buf) const override;
private:
Defined *Sym;
Defined *sym;
};
// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
// offset into the chunk. Order does not matter as the RVA table will be sorted
// later.
struct ChunkAndOffset {
Chunk *InputChunk;
uint32_t Offset;
Chunk *inputChunk;
uint32_t offset;
struct DenseMapInfo {
static ChunkAndOffset getEmptyKey() {
@ -550,12 +550,12 @@ struct ChunkAndOffset {
static ChunkAndOffset getTombstoneKey() {
return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
}
static unsigned getHashValue(const ChunkAndOffset &CO) {
static unsigned getHashValue(const ChunkAndOffset &co) {
return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
{CO.InputChunk, CO.Offset});
{co.inputChunk, co.offset});
}
static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) {
return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset;
static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) {
return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset;
}
};
};
@ -565,12 +565,12 @@ using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;
// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
class RVATableChunk : public NonSectionChunk {
public:
explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {}
size_t getSize() const override { return Syms.size() * 4; }
void writeTo(uint8_t *Buf) const override;
explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {}
size_t getSize() const override { return syms.size() * 4; }
void writeTo(uint8_t *buf) const override;
private:
SymbolRVASet Syms;
SymbolRVASet syms;
};
// Windows-specific.
@ -578,22 +578,22 @@ private:
// See the PE/COFF spec 5.6 for details.
class BaserelChunk : public NonSectionChunk {
public:
BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
size_t getSize() const override { return Data.size(); }
void writeTo(uint8_t *Buf) const override;
BaserelChunk(uint32_t page, Baserel *begin, Baserel *end);
size_t getSize() const override { return data.size(); }
void writeTo(uint8_t *buf) const override;
private:
std::vector<uint8_t> Data;
std::vector<uint8_t> data;
};
class Baserel {
public:
Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {}
explicit Baserel(uint32_t v) : Baserel(v, getDefaultType()) {}
uint8_t getDefaultType();
uint32_t RVA;
uint8_t Type;
uint32_t rva;
uint8_t type;
};
// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a
@ -604,7 +604,7 @@ class EmptyChunk : public NonSectionChunk {
public:
EmptyChunk() {}
size_t getSize() const override { return 0; }
void writeTo(uint8_t *Buf) const override {}
void writeTo(uint8_t *buf) const override {}
};
// MinGW specific, for the "automatic import of variables from DLLs" feature.
@ -615,15 +615,15 @@ public:
// code.
class PseudoRelocTableChunk : public NonSectionChunk {
public:
PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &Relocs)
: Relocs(std::move(Relocs)) {
PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &relocs)
: relocs(std::move(relocs)) {
setAlignment(4);
}
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *buf) const override;
private:
std::vector<RuntimePseudoReloc> Relocs;
std::vector<RuntimePseudoReloc> relocs;
};
// MinGW specific; information about one individual location in the image
@ -631,48 +631,48 @@ private:
// one individual element in the PseudoRelocTableChunk table.
class RuntimePseudoReloc {
public:
RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset,
int Flags)
: Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {}
RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset,
int flags)
: sym(sym), target(target), targetOffset(targetOffset), flags(flags) {}
Defined *Sym;
SectionChunk *Target;
uint32_t TargetOffset;
Defined *sym;
SectionChunk *target;
uint32_t targetOffset;
// The Flags field contains the size of the relocation, in bits. No other
// flags are currently defined.
int Flags;
int flags;
};
// MinGW specific. A Chunk that contains one pointer-sized absolute value.
class AbsolutePointerChunk : public NonSectionChunk {
public:
AbsolutePointerChunk(uint64_t Value) : Value(Value) {
AbsolutePointerChunk(uint64_t value) : value(value) {
setAlignment(getSize());
}
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *buf) const override;
private:
uint64_t Value;
uint64_t value;
};
// Return true if this file has the hotpatch flag set to true in the S_COMPILE3
// record in codeview debug info. Also returns true for some thunks synthesized
// by the linker.
inline bool Chunk::isHotPatchable() const {
if (auto *SC = dyn_cast<SectionChunk>(this))
return SC->File->HotPatchable;
if (auto *sc = dyn_cast<SectionChunk>(this))
return sc->file->hotPatchable;
else if (isa<ImportThunkChunk>(this))
return true;
return false;
}
void applyMOV32T(uint8_t *Off, uint32_t V);
void applyBranch24T(uint8_t *Off, int32_t V);
void applyMOV32T(uint8_t *off, uint32_t v);
void applyBranch24T(uint8_t *off, int32_t v);
void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift);
void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit);
void applyArm64Branch26(uint8_t *Off, int64_t V);
void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift);
void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit);
void applyArm64Branch26(uint8_t *off, int64_t v);
} // namespace coff
} // namespace lld

View File

@ -38,30 +38,30 @@ static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
// Represents an /export option.
struct Export {
StringRef Name; // N in /export:N or /export:E=N
StringRef ExtName; // E in /export:E=N
Symbol *Sym = nullptr;
uint16_t Ordinal = 0;
bool Noname = false;
bool Data = false;
bool Private = false;
bool Constant = false;
StringRef name; // N in /export:N or /export:E=N
StringRef extName; // E in /export:E=N
Symbol *sym = nullptr;
uint16_t ordinal = 0;
bool noname = false;
bool data = false;
bool isPrivate = false;
bool constant = false;
// If an export is a form of /export:foo=dllname.bar, that means
// that foo should be exported as an alias to bar in the DLL.
// ForwardTo is set to "dllname.bar" part. Usually empty.
StringRef ForwardTo;
StringChunk *ForwardChunk = nullptr;
StringRef forwardTo;
StringChunk *forwardChunk = nullptr;
// True if this /export option was in .drectves section.
bool Directives = false;
StringRef SymbolName;
StringRef ExportName; // Name in DLL
bool directives = false;
StringRef symbolName;
StringRef exportName; // Name in DLL
bool operator==(const Export &E) {
return (Name == E.Name && ExtName == E.ExtName &&
Ordinal == E.Ordinal && Noname == E.Noname &&
Data == E.Data && Private == E.Private);
bool operator==(const Export &e) {
return (name == e.name && extName == e.extName &&
ordinal == e.ordinal && noname == e.noname &&
data == e.data && isPrivate == e.isPrivate);
}
};
@ -81,137 +81,137 @@ enum class GuardCFLevel {
// Global configuration.
struct Configuration {
enum ManifestKind { SideBySide, Embed, No };
bool is64() { return Machine == AMD64 || Machine == ARM64; }
bool is64() { return machine == AMD64 || machine == ARM64; }
llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
size_t Wordsize;
bool Verbose = false;
WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
Symbol *Entry = nullptr;
bool NoEntry = false;
std::string OutputFile;
std::string ImportName;
bool Demangle = true;
bool DoGC = true;
bool DoICF = true;
bool TailMerge;
bool Relocatable = true;
bool ForceMultiple = false;
bool ForceMultipleRes = false;
bool ForceUnresolved = false;
bool Debug = false;
bool DebugDwarf = false;
bool DebugGHashes = false;
bool DebugSymtab = false;
bool ShowTiming = false;
bool ShowSummary = false;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
std::vector<std::string> NatvisFiles;
llvm::SmallString<128> PDBAltPath;
llvm::SmallString<128> PDBPath;
llvm::SmallString<128> PDBSourcePath;
std::vector<llvm::StringRef> Argv;
llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN;
size_t wordsize;
bool verbose = false;
WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
Symbol *entry = nullptr;
bool noEntry = false;
std::string outputFile;
std::string importName;
bool demangle = true;
bool doGC = true;
bool doICF = true;
bool tailMerge;
bool relocatable = true;
bool forceMultiple = false;
bool forceMultipleRes = false;
bool forceUnresolved = false;
bool debug = false;
bool debugDwarf = false;
bool debugGHashes = false;
bool debugSymtab = false;
bool showTiming = false;
bool showSummary = false;
unsigned debugTypes = static_cast<unsigned>(DebugType::None);
std::vector<std::string> natvisFiles;
llvm::SmallString<128> pdbAltPath;
llvm::SmallString<128> pdbPath;
llvm::SmallString<128> pdbSourcePath;
std::vector<llvm::StringRef> argv;
// Symbols in this set are considered as live by the garbage collector.
std::vector<Symbol *> GCRoot;
std::vector<Symbol *> gCRoot;
std::set<std::string> NoDefaultLibs;
bool NoDefaultLibAll = false;
std::set<std::string> noDefaultLibs;
bool noDefaultLibAll = false;
// True if we are creating a DLL.
bool DLL = false;
StringRef Implib;
std::vector<Export> Exports;
std::set<std::string> DelayLoads;
std::map<std::string, int> DLLOrder;
Symbol *DelayLoadHelper = nullptr;
bool dll = false;
StringRef implib;
std::vector<Export> exports;
std::set<std::string> delayLoads;
std::map<std::string, int> dllOrder;
Symbol *delayLoadHelper = nullptr;
bool SaveTemps = false;
bool saveTemps = false;
// /guard:cf
GuardCFLevel GuardCF = GuardCFLevel::Off;
GuardCFLevel guardCF = GuardCFLevel::Off;
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
Symbol *sehTable = nullptr;
Symbol *sehCount = nullptr;
// Used for /opt:lldlto=N
unsigned LTOO = 2;
unsigned ltoo = 2;
// Used for /opt:lldltojobs=N
unsigned ThinLTOJobs = 0;
unsigned thinLTOJobs = 0;
// Used for /opt:lldltopartitions=N
unsigned LTOPartitions = 1;
unsigned ltoPartitions = 1;
// Used for /opt:lldltocache=path
StringRef LTOCache;
StringRef ltoCache;
// Used for /opt:lldltocachepolicy=policy
llvm::CachePruningPolicy LTOCachePolicy;
llvm::CachePruningPolicy ltoCachePolicy;
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge;
std::map<StringRef, StringRef> merge;
// Used for /section=.name,{DEKPRSW} to set section attributes.
std::map<StringRef, uint32_t> Section;
std::map<StringRef, uint32_t> section;
// Options for manifest files.
ManifestKind Manifest = No;
int ManifestID = 1;
StringRef ManifestDependency;
bool ManifestUAC = true;
std::vector<std::string> ManifestInput;
StringRef ManifestLevel = "'asInvoker'";
StringRef ManifestUIAccess = "'false'";
StringRef ManifestFile;
ManifestKind manifest = No;
int manifestID = 1;
StringRef manifestDependency;
bool manifestUAC = true;
std::vector<std::string> manifestInput;
StringRef manifestLevel = "'asInvoker'";
StringRef manifestUIAccess = "'false'";
StringRef manifestFile;
// Used for /aligncomm.
std::map<std::string, int> AlignComm;
std::map<std::string, int> alignComm;
// Used for /failifmismatch.
std::map<StringRef, std::pair<StringRef, InputFile *>> MustMatch;
std::map<StringRef, std::pair<StringRef, InputFile *>> mustMatch;
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
std::map<StringRef, StringRef> alternateNames;
// Used for /order.
llvm::StringMap<int> Order;
llvm::StringMap<int> order;
// Used for /lldmap.
std::string MapFile;
std::string mapFile;
uint64_t ImageBase = -1;
uint64_t FileAlign = 512;
uint64_t StackReserve = 1024 * 1024;
uint64_t StackCommit = 4096;
uint64_t HeapReserve = 1024 * 1024;
uint64_t HeapCommit = 4096;
uint32_t MajorImageVersion = 0;
uint32_t MinorImageVersion = 0;
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
uint32_t Timestamp = 0;
uint32_t FunctionPadMin = 0;
bool DynamicBase = true;
bool AllowBind = true;
bool NxCompat = true;
bool AllowIsolation = true;
bool TerminalServerAware = true;
bool LargeAddressAware = false;
bool HighEntropyVA = false;
bool AppContainer = false;
bool MinGW = false;
bool WarnMissingOrderSymbol = true;
bool WarnLocallyDefinedImported = true;
bool WarnDebugInfoUnusable = true;
bool Incremental = true;
bool IntegrityCheck = false;
bool KillAt = false;
bool Repro = false;
bool SwaprunCD = false;
bool SwaprunNet = false;
uint64_t imageBase = -1;
uint64_t fileAlign = 512;
uint64_t stackReserve = 1024 * 1024;
uint64_t stackCommit = 4096;
uint64_t heapReserve = 1024 * 1024;
uint64_t heapCommit = 4096;
uint32_t majorImageVersion = 0;
uint32_t minorImageVersion = 0;
uint32_t majorOSVersion = 6;
uint32_t minorOSVersion = 0;
uint32_t timestamp = 0;
uint32_t functionPadMin = 0;
bool dynamicBase = true;
bool allowBind = true;
bool nxCompat = true;
bool allowIsolation = true;
bool terminalServerAware = true;
bool largeAddressAware = false;
bool highEntropyVA = false;
bool appContainer = false;
bool mingw = false;
bool warnMissingOrderSymbol = true;
bool warnLocallyDefinedImported = true;
bool warnDebugInfoUnusable = true;
bool incremental = true;
bool integrityCheck = false;
bool killAt = false;
bool repro = false;
bool swaprunCD = false;
bool swaprunNet = false;
};
extern Configuration *Config;
extern Configuration *config;
} // namespace coff
} // namespace lld

View File

@ -37,41 +37,41 @@ namespace {
// A chunk for the import descriptor table.
class HintNameChunk : public NonSectionChunk {
public:
HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {}
size_t getSize() const override {
// Starts with 2 byte Hint field, followed by a null-terminated string,
// ends with 0 or 1 byte padding.
return alignTo(Name.size() + 3, 2);
return alignTo(name.size() + 3, 2);
}
void writeTo(uint8_t *Buf) const override {
memset(Buf, 0, getSize());
write16le(Buf, Hint);
memcpy(Buf + 2, Name.data(), Name.size());
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
write16le(buf, hint);
memcpy(buf + 2, name.data(), name.size());
}
private:
StringRef Name;
uint16_t Hint;
StringRef name;
uint16_t hint;
};
// A chunk for the import descriptor table.
class LookupChunk : public NonSectionChunk {
public:
explicit LookupChunk(Chunk *C) : HintName(C) {
setAlignment(Config->Wordsize);
explicit LookupChunk(Chunk *c) : hintName(c) {
setAlignment(config->wordsize);
}
size_t getSize() const override { return Config->Wordsize; }
size_t getSize() const override { return config->wordsize; }
void writeTo(uint8_t *Buf) const override {
if (Config->is64())
write64le(Buf, HintName->getRVA());
void writeTo(uint8_t *buf) const override {
if (config->is64())
write64le(buf, hintName->getRVA());
else
write32le(Buf, HintName->getRVA());
write32le(buf, hintName->getRVA());
}
Chunk *HintName;
Chunk *hintName;
};
// A chunk for the import descriptor table.
@ -79,82 +79,82 @@ public:
// See Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public NonSectionChunk {
public:
explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {
setAlignment(Config->Wordsize);
explicit OrdinalOnlyChunk(uint16_t v) : ordinal(v) {
setAlignment(config->wordsize);
}
size_t getSize() const override { return Config->Wordsize; }
size_t getSize() const override { return config->wordsize; }
void writeTo(uint8_t *Buf) const override {
void writeTo(uint8_t *buf) const override {
// An import-by-ordinal slot has MSB 1 to indicate that
// this is import-by-ordinal (and not import-by-name).
if (Config->is64()) {
write64le(Buf, (1ULL << 63) | Ordinal);
if (config->is64()) {
write64le(buf, (1ULL << 63) | ordinal);
} else {
write32le(Buf, (1ULL << 31) | Ordinal);
write32le(buf, (1ULL << 31) | ordinal);
}
}
uint16_t Ordinal;
uint16_t ordinal;
};
// A chunk for the import descriptor table.
class ImportDirectoryChunk : public NonSectionChunk {
public:
explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
explicit ImportDirectoryChunk(Chunk *n) : dllName(n) {}
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
void writeTo(uint8_t *Buf) const override {
memset(Buf, 0, getSize());
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
auto *E = (coff_import_directory_table_entry *)(Buf);
E->ImportLookupTableRVA = LookupTab->getRVA();
E->NameRVA = DLLName->getRVA();
E->ImportAddressTableRVA = AddressTab->getRVA();
auto *e = (coff_import_directory_table_entry *)(buf);
e->ImportLookupTableRVA = lookupTab->getRVA();
e->NameRVA = dllName->getRVA();
e->ImportAddressTableRVA = addressTab->getRVA();
}
Chunk *DLLName;
Chunk *LookupTab;
Chunk *AddressTab;
Chunk *dllName;
Chunk *lookupTab;
Chunk *addressTab;
};
// A chunk representing null terminator in the import table.
// Contents of this chunk is always null bytes.
class NullChunk : public NonSectionChunk {
public:
explicit NullChunk(size_t N) : Size(N) { HasData = false; }
size_t getSize() const override { return Size; }
explicit NullChunk(size_t n) : size(n) { hasData = false; }
size_t getSize() const override { return size; }
void writeTo(uint8_t *Buf) const override {
memset(Buf, 0, Size);
void writeTo(uint8_t *buf) const override {
memset(buf, 0, size);
}
private:
size_t Size;
size_t size;
};
static std::vector<std::vector<DefinedImportData *>>
binImports(const std::vector<DefinedImportData *> &Imports) {
binImports(const std::vector<DefinedImportData *> &imports) {
// Group DLL-imported symbols by DLL name because that's how
// symbols are layed out in the import descriptor table.
auto Less = [](const std::string &A, const std::string &B) {
return Config->DLLOrder[A] < Config->DLLOrder[B];
auto less = [](const std::string &a, const std::string &b) {
return config->dllOrder[a] < config->dllOrder[b];
};
std::map<std::string, std::vector<DefinedImportData *>,
bool(*)(const std::string &, const std::string &)> M(Less);
for (DefinedImportData *Sym : Imports)
M[Sym->getDLLName().lower()].push_back(Sym);
bool(*)(const std::string &, const std::string &)> m(less);
for (DefinedImportData *sym : imports)
m[sym->getDLLName().lower()].push_back(sym);
std::vector<std::vector<DefinedImportData *>> V;
for (auto &KV : M) {
std::vector<std::vector<DefinedImportData *>> v;
for (auto &kv : m) {
// Sort symbols by name for each group.
std::vector<DefinedImportData *> &Syms = KV.second;
std::sort(Syms.begin(), Syms.end(),
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
std::vector<DefinedImportData *> &syms = kv.second;
std::sort(syms.begin(), syms.end(),
[](DefinedImportData *a, DefinedImportData *b) {
return a->getName() < b->getName();
});
V.push_back(std::move(Syms));
v.push_back(std::move(syms));
}
return V;
return v;
}
// Export table
@ -163,34 +163,34 @@ binImports(const std::vector<DefinedImportData *> &Imports) {
// A chunk for the delay import descriptor table etnry.
class DelayDirectoryChunk : public NonSectionChunk {
public:
explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
explicit DelayDirectoryChunk(Chunk *n) : dllName(n) {}
size_t getSize() const override {
return sizeof(delay_import_directory_table_entry);
}
void writeTo(uint8_t *Buf) const override {
memset(Buf, 0, getSize());
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
auto *E = (delay_import_directory_table_entry *)(Buf);
E->Attributes = 1;
E->Name = DLLName->getRVA();
E->ModuleHandle = ModuleHandle->getRVA();
E->DelayImportAddressTable = AddressTab->getRVA();
E->DelayImportNameTable = NameTab->getRVA();
auto *e = (delay_import_directory_table_entry *)(buf);
e->Attributes = 1;
e->Name = dllName->getRVA();
e->ModuleHandle = moduleHandle->getRVA();
e->DelayImportAddressTable = addressTab->getRVA();
e->DelayImportNameTable = nameTab->getRVA();
}
Chunk *DLLName;
Chunk *ModuleHandle;
Chunk *AddressTab;
Chunk *NameTab;
Chunk *dllName;
Chunk *moduleHandle;
Chunk *addressTab;
Chunk *nameTab;
};
// Initial contents for delay-loaded functions.
// This code calls __delayLoadHelper2 function to resolve a symbol
// and then overwrites its jump table slot with the result
// for subsequent function calls.
static const uint8_t ThunkX64[] = {
static const uint8_t thunkX64[] = {
0x51, // push rcx
0x52, // push rdx
0x41, 0x50, // push r8
@ -215,7 +215,7 @@ static const uint8_t ThunkX64[] = {
0xFF, 0xE0, // jmp rax
};
static const uint8_t ThunkX86[] = {
static const uint8_t thunkX86[] = {
0x51, // push ecx
0x52, // push edx
0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
@ -226,7 +226,7 @@ static const uint8_t ThunkX86[] = {
0xFF, 0xE0, // jmp eax
};
static const uint8_t ThunkARM[] = {
static const uint8_t thunkARM[] = {
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr}
@ -242,7 +242,7 @@ static const uint8_t ThunkARM[] = {
0x60, 0x47, // bx ip
};
static const uint8_t ThunkARM64[] = {
static const uint8_t thunkARM64[] = {
0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
@ -275,117 +275,117 @@ static const uint8_t ThunkARM64[] = {
// A chunk for the delay import thunk.
class ThunkChunkX64 : public NonSectionChunk {
public:
ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
: Imp(I), Desc(D), Helper(H) {}
ThunkChunkX64(Defined *i, Chunk *d, Defined *h)
: imp(i), desc(d), helper(h) {}
size_t getSize() const override { return sizeof(ThunkX64); }
size_t getSize() const override { return sizeof(thunkX64); }
void writeTo(uint8_t *Buf) const override {
memcpy(Buf, ThunkX64, sizeof(ThunkX64));
write32le(Buf + 36, Imp->getRVA() - RVA - 40);
write32le(Buf + 43, Desc->getRVA() - RVA - 47);
write32le(Buf + 48, Helper->getRVA() - RVA - 52);
void writeTo(uint8_t *buf) const override {
memcpy(buf, thunkX64, sizeof(thunkX64));
write32le(buf + 36, imp->getRVA() - rva - 40);
write32le(buf + 43, desc->getRVA() - rva - 47);
write32le(buf + 48, helper->getRVA() - rva - 52);
}
Defined *Imp = nullptr;
Chunk *Desc = nullptr;
Defined *Helper = nullptr;
Defined *imp = nullptr;
Chunk *desc = nullptr;
Defined *helper = nullptr;
};
class ThunkChunkX86 : public NonSectionChunk {
public:
ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
: Imp(I), Desc(D), Helper(H) {}
ThunkChunkX86(Defined *i, Chunk *d, Defined *h)
: imp(i), desc(d), helper(h) {}
size_t getSize() const override { return sizeof(ThunkX86); }
size_t getSize() const override { return sizeof(thunkX86); }
void writeTo(uint8_t *Buf) const override {
memcpy(Buf, ThunkX86, sizeof(ThunkX86));
write32le(Buf + 3, Imp->getRVA() + Config->ImageBase);
write32le(Buf + 8, Desc->getRVA() + Config->ImageBase);
write32le(Buf + 13, Helper->getRVA() - RVA - 17);
void writeTo(uint8_t *buf) const override {
memcpy(buf, thunkX86, sizeof(thunkX86));
write32le(buf + 3, imp->getRVA() + config->imageBase);
write32le(buf + 8, desc->getRVA() + config->imageBase);
write32le(buf + 13, helper->getRVA() - rva - 17);
}
void getBaserels(std::vector<Baserel> *Res) override {
Res->emplace_back(RVA + 3);
Res->emplace_back(RVA + 8);
void getBaserels(std::vector<Baserel> *res) override {
res->emplace_back(rva + 3);
res->emplace_back(rva + 8);
}
Defined *Imp = nullptr;
Chunk *Desc = nullptr;
Defined *Helper = nullptr;
Defined *imp = nullptr;
Chunk *desc = nullptr;
Defined *helper = nullptr;
};
class ThunkChunkARM : public NonSectionChunk {
public:
ThunkChunkARM(Defined *I, Chunk *D, Defined *H)
: Imp(I), Desc(D), Helper(H) {}
ThunkChunkARM(Defined *i, Chunk *d, Defined *h)
: imp(i), desc(d), helper(h) {}
size_t getSize() const override { return sizeof(ThunkARM); }
size_t getSize() const override { return sizeof(thunkARM); }
void writeTo(uint8_t *Buf) const override {
memcpy(Buf, ThunkARM, sizeof(ThunkARM));
applyMOV32T(Buf + 0, Imp->getRVA() + Config->ImageBase);
applyMOV32T(Buf + 22, Desc->getRVA() + Config->ImageBase);
applyBranch24T(Buf + 30, Helper->getRVA() - RVA - 34);
void writeTo(uint8_t *buf) const override {
memcpy(buf, thunkARM, sizeof(thunkARM));
applyMOV32T(buf + 0, imp->getRVA() + config->imageBase);
applyMOV32T(buf + 22, desc->getRVA() + config->imageBase);
applyBranch24T(buf + 30, helper->getRVA() - rva - 34);
}
void getBaserels(std::vector<Baserel> *Res) override {
Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T);
Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T);
void getBaserels(std::vector<Baserel> *res) override {
res->emplace_back(rva + 0, IMAGE_REL_BASED_ARM_MOV32T);
res->emplace_back(rva + 22, IMAGE_REL_BASED_ARM_MOV32T);
}
Defined *Imp = nullptr;
Chunk *Desc = nullptr;
Defined *Helper = nullptr;
Defined *imp = nullptr;
Chunk *desc = nullptr;
Defined *helper = nullptr;
};
class ThunkChunkARM64 : public NonSectionChunk {
public:
ThunkChunkARM64(Defined *I, Chunk *D, Defined *H)
: Imp(I), Desc(D), Helper(H) {}
ThunkChunkARM64(Defined *i, Chunk *d, Defined *h)
: imp(i), desc(d), helper(h) {}
size_t getSize() const override { return sizeof(ThunkARM64); }
size_t getSize() const override { return sizeof(thunkARM64); }
void writeTo(uint8_t *Buf) const override {
memcpy(Buf, ThunkARM64, sizeof(ThunkARM64));
applyArm64Addr(Buf + 0, Imp->getRVA(), RVA + 0, 12);
applyArm64Imm(Buf + 4, Imp->getRVA() & 0xfff, 0);
applyArm64Addr(Buf + 52, Desc->getRVA(), RVA + 52, 12);
applyArm64Imm(Buf + 56, Desc->getRVA() & 0xfff, 0);
applyArm64Branch26(Buf + 60, Helper->getRVA() - RVA - 60);
void writeTo(uint8_t *buf) const override {
memcpy(buf, thunkARM64, sizeof(thunkARM64));
applyArm64Addr(buf + 0, imp->getRVA(), rva + 0, 12);
applyArm64Imm(buf + 4, imp->getRVA() & 0xfff, 0);
applyArm64Addr(buf + 52, desc->getRVA(), rva + 52, 12);
applyArm64Imm(buf + 56, desc->getRVA() & 0xfff, 0);
applyArm64Branch26(buf + 60, helper->getRVA() - rva - 60);
}
Defined *Imp = nullptr;
Chunk *Desc = nullptr;
Defined *Helper = nullptr;
Defined *imp = nullptr;
Chunk *desc = nullptr;
Defined *helper = nullptr;
};
// A chunk for the import descriptor table.
class DelayAddressChunk : public NonSectionChunk {
public:
explicit DelayAddressChunk(Chunk *C) : Thunk(C) {
setAlignment(Config->Wordsize);
explicit DelayAddressChunk(Chunk *c) : thunk(c) {
setAlignment(config->wordsize);
}
size_t getSize() const override { return Config->Wordsize; }
size_t getSize() const override { return config->wordsize; }
void writeTo(uint8_t *Buf) const override {
if (Config->is64()) {
write64le(Buf, Thunk->getRVA() + Config->ImageBase);
void writeTo(uint8_t *buf) const override {
if (config->is64()) {
write64le(buf, thunk->getRVA() + config->imageBase);
} else {
uint32_t Bit = 0;
uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
if (Config->Machine == ARMNT)
Bit = 1;
write32le(Buf, (Thunk->getRVA() + Config->ImageBase) | Bit);
if (config->machine == ARMNT)
bit = 1;
write32le(buf, (thunk->getRVA() + config->imageBase) | bit);
}
}
void getBaserels(std::vector<Baserel> *Res) override {
Res->emplace_back(RVA);
void getBaserels(std::vector<Baserel> *res) override {
res->emplace_back(rva);
}
Chunk *Thunk;
Chunk *thunk;
};
// Export table
@ -394,248 +394,248 @@ public:
// A chunk for the export descriptor table.
class ExportDirectoryChunk : public NonSectionChunk {
public:
ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
: MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
OrdinalTab(O) {}
ExportDirectoryChunk(int i, int j, Chunk *d, Chunk *a, Chunk *n, Chunk *o)
: maxOrdinal(i), nameTabSize(j), dllName(d), addressTab(a), nameTab(n),
ordinalTab(o) {}
size_t getSize() const override {
return sizeof(export_directory_table_entry);
}
void writeTo(uint8_t *Buf) const override {
memset(Buf, 0, getSize());
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
auto *E = (export_directory_table_entry *)(Buf);
E->NameRVA = DLLName->getRVA();
E->OrdinalBase = 0;
E->AddressTableEntries = MaxOrdinal + 1;
E->NumberOfNamePointers = NameTabSize;
E->ExportAddressTableRVA = AddressTab->getRVA();
E->NamePointerRVA = NameTab->getRVA();
E->OrdinalTableRVA = OrdinalTab->getRVA();
auto *e = (export_directory_table_entry *)(buf);
e->NameRVA = dllName->getRVA();
e->OrdinalBase = 0;
e->AddressTableEntries = maxOrdinal + 1;
e->NumberOfNamePointers = nameTabSize;
e->ExportAddressTableRVA = addressTab->getRVA();
e->NamePointerRVA = nameTab->getRVA();
e->OrdinalTableRVA = ordinalTab->getRVA();
}
uint16_t MaxOrdinal;
uint16_t NameTabSize;
Chunk *DLLName;
Chunk *AddressTab;
Chunk *NameTab;
Chunk *OrdinalTab;
uint16_t maxOrdinal;
uint16_t nameTabSize;
Chunk *dllName;
Chunk *addressTab;
Chunk *nameTab;
Chunk *ordinalTab;
};
class AddressTableChunk : public NonSectionChunk {
public:
explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
size_t getSize() const override { return Size * 4; }
explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal + 1) {}
size_t getSize() const override { return size * 4; }
void writeTo(uint8_t *Buf) const override {
memset(Buf, 0, getSize());
void writeTo(uint8_t *buf) const override {
memset(buf, 0, getSize());
for (const Export &E : Config->Exports) {
uint8_t *P = Buf + E.Ordinal * 4;
uint32_t Bit = 0;
for (const Export &e : config->exports) {
uint8_t *p = buf + e.ordinal * 4;
uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
if (Config->Machine == ARMNT && !E.Data)
Bit = 1;
if (E.ForwardChunk) {
write32le(P, E.ForwardChunk->getRVA() | Bit);
if (config->machine == ARMNT && !e.data)
bit = 1;
if (e.forwardChunk) {
write32le(p, e.forwardChunk->getRVA() | bit);
} else {
write32le(P, cast<Defined>(E.Sym)->getRVA() | Bit);
write32le(p, cast<Defined>(e.sym)->getRVA() | bit);
}
}
}
private:
size_t Size;
size_t size;
};
class NamePointersChunk : public NonSectionChunk {
public:
explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
size_t getSize() const override { return Chunks.size() * 4; }
explicit NamePointersChunk(std::vector<Chunk *> &v) : chunks(v) {}
size_t getSize() const override { return chunks.size() * 4; }
void writeTo(uint8_t *Buf) const override {
for (Chunk *C : Chunks) {
write32le(Buf, C->getRVA());
Buf += 4;
void writeTo(uint8_t *buf) const override {
for (Chunk *c : chunks) {
write32le(buf, c->getRVA());
buf += 4;
}
}
private:
std::vector<Chunk *> Chunks;
std::vector<Chunk *> chunks;
};
class ExportOrdinalChunk : public NonSectionChunk {
public:
explicit ExportOrdinalChunk(size_t I) : Size(I) {}
size_t getSize() const override { return Size * 2; }
explicit ExportOrdinalChunk(size_t i) : size(i) {}
size_t getSize() const override { return size * 2; }
void writeTo(uint8_t *Buf) const override {
for (Export &E : Config->Exports) {
if (E.Noname)
void writeTo(uint8_t *buf) const override {
for (Export &e : config->exports) {
if (e.noname)
continue;
write16le(Buf, E.Ordinal);
Buf += 2;
write16le(buf, e.ordinal);
buf += 2;
}
}
private:
size_t Size;
size_t size;
};
} // anonymous namespace
void IdataContents::create() {
std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
// Create .idata contents for each DLL.
for (std::vector<DefinedImportData *> &Syms : V) {
for (std::vector<DefinedImportData *> &syms : v) {
// Create lookup and address tables. If they have external names,
// we need to create HintName chunks to store the names.
// If they don't (if they are import-by-ordinals), we store only
// ordinal values to the table.
size_t Base = Lookups.size();
for (DefinedImportData *S : Syms) {
uint16_t Ord = S->getOrdinal();
if (S->getExternalName().empty()) {
Lookups.push_back(make<OrdinalOnlyChunk>(Ord));
Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
size_t base = lookups.size();
for (DefinedImportData *s : syms) {
uint16_t ord = s->getOrdinal();
if (s->getExternalName().empty()) {
lookups.push_back(make<OrdinalOnlyChunk>(ord));
addresses.push_back(make<OrdinalOnlyChunk>(ord));
continue;
}
auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
Lookups.push_back(make<LookupChunk>(C));
Addresses.push_back(make<LookupChunk>(C));
Hints.push_back(C);
auto *c = make<HintNameChunk>(s->getExternalName(), ord);
lookups.push_back(make<LookupChunk>(c));
addresses.push_back(make<LookupChunk>(c));
hints.push_back(c);
}
// Terminate with null values.
Lookups.push_back(make<NullChunk>(Config->Wordsize));
Addresses.push_back(make<NullChunk>(Config->Wordsize));
lookups.push_back(make<NullChunk>(config->wordsize));
addresses.push_back(make<NullChunk>(config->wordsize));
for (int I = 0, E = Syms.size(); I < E; ++I)
Syms[I]->setLocation(Addresses[Base + I]);
for (int i = 0, e = syms.size(); i < e; ++i)
syms[i]->setLocation(addresses[base + i]);
// Create the import table header.
DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
Dir->LookupTab = Lookups[Base];
Dir->AddressTab = Addresses[Base];
Dirs.push_back(Dir);
dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
auto *dir = make<ImportDirectoryChunk>(dllNames.back());
dir->lookupTab = lookups[base];
dir->addressTab = addresses[base];
dirs.push_back(dir);
}
// Add null terminator.
Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
}
std::vector<Chunk *> DelayLoadContents::getChunks() {
std::vector<Chunk *> V;
V.insert(V.end(), Dirs.begin(), Dirs.end());
V.insert(V.end(), Names.begin(), Names.end());
V.insert(V.end(), HintNames.begin(), HintNames.end());
V.insert(V.end(), DLLNames.begin(), DLLNames.end());
return V;
std::vector<Chunk *> v;
v.insert(v.end(), dirs.begin(), dirs.end());
v.insert(v.end(), names.begin(), names.end());
v.insert(v.end(), hintNames.begin(), hintNames.end());
v.insert(v.end(), dllNames.begin(), dllNames.end());
return v;
}
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
std::vector<Chunk *> V;
V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
V.insert(V.end(), Addresses.begin(), Addresses.end());
return V;
std::vector<Chunk *> v;
v.insert(v.end(), moduleHandles.begin(), moduleHandles.end());
v.insert(v.end(), addresses.begin(), addresses.end());
return v;
}
uint64_t DelayLoadContents::getDirSize() {
return Dirs.size() * sizeof(delay_import_directory_table_entry);
return dirs.size() * sizeof(delay_import_directory_table_entry);
}
void DelayLoadContents::create(Defined *H) {
Helper = H;
std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
void DelayLoadContents::create(Defined *h) {
helper = h;
std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
// Create .didat contents for each DLL.
for (std::vector<DefinedImportData *> &Syms : V) {
for (std::vector<DefinedImportData *> &syms : v) {
// Create the delay import table header.
DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
auto *dir = make<DelayDirectoryChunk>(dllNames.back());
size_t Base = Addresses.size();
for (DefinedImportData *S : Syms) {
Chunk *T = newThunkChunk(S, Dir);
auto *A = make<DelayAddressChunk>(T);
Addresses.push_back(A);
Thunks.push_back(T);
StringRef ExtName = S->getExternalName();
if (ExtName.empty()) {
Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
size_t base = addresses.size();
for (DefinedImportData *s : syms) {
Chunk *t = newThunkChunk(s, dir);
auto *a = make<DelayAddressChunk>(t);
addresses.push_back(a);
thunks.push_back(t);
StringRef extName = s->getExternalName();
if (extName.empty()) {
names.push_back(make<OrdinalOnlyChunk>(s->getOrdinal()));
} else {
auto *C = make<HintNameChunk>(ExtName, 0);
Names.push_back(make<LookupChunk>(C));
HintNames.push_back(C);
auto *c = make<HintNameChunk>(extName, 0);
names.push_back(make<LookupChunk>(c));
hintNames.push_back(c);
}
}
// Terminate with null values.
Addresses.push_back(make<NullChunk>(8));
Names.push_back(make<NullChunk>(8));
addresses.push_back(make<NullChunk>(8));
names.push_back(make<NullChunk>(8));
for (int I = 0, E = Syms.size(); I < E; ++I)
Syms[I]->setLocation(Addresses[Base + I]);
auto *MH = make<NullChunk>(8);
MH->setAlignment(8);
ModuleHandles.push_back(MH);
for (int i = 0, e = syms.size(); i < e; ++i)
syms[i]->setLocation(addresses[base + i]);
auto *mh = make<NullChunk>(8);
mh->setAlignment(8);
moduleHandles.push_back(mh);
// Fill the delay import table header fields.
Dir->ModuleHandle = MH;
Dir->AddressTab = Addresses[Base];
Dir->NameTab = Names[Base];
Dirs.push_back(Dir);
dir->moduleHandle = mh;
dir->addressTab = addresses[base];
dir->nameTab = names[base];
dirs.push_back(dir);
}
// Add null terminator.
Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
}
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
switch (Config->Machine) {
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s, Chunk *dir) {
switch (config->machine) {
case AMD64:
return make<ThunkChunkX64>(S, Dir, Helper);
return make<ThunkChunkX64>(s, dir, helper);
case I386:
return make<ThunkChunkX86>(S, Dir, Helper);
return make<ThunkChunkX86>(s, dir, helper);
case ARMNT:
return make<ThunkChunkARM>(S, Dir, Helper);
return make<ThunkChunkARM>(s, dir, helper);
case ARM64:
return make<ThunkChunkARM64>(S, Dir, Helper);
return make<ThunkChunkARM64>(s, dir, helper);
default:
llvm_unreachable("unsupported machine type");
}
}
EdataContents::EdataContents() {
uint16_t MaxOrdinal = 0;
for (Export &E : Config->Exports)
MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
uint16_t maxOrdinal = 0;
for (Export &e : config->exports)
maxOrdinal = std::max(maxOrdinal, e.ordinal);
auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
std::vector<Chunk *> Names;
for (Export &E : Config->Exports)
if (!E.Noname)
Names.push_back(make<StringChunk>(E.ExportName));
auto *dllName = make<StringChunk>(sys::path::filename(config->outputFile));
auto *addressTab = make<AddressTableChunk>(maxOrdinal);
std::vector<Chunk *> names;
for (Export &e : config->exports)
if (!e.noname)
names.push_back(make<StringChunk>(e.exportName));
std::vector<Chunk *> Forwards;
for (Export &E : Config->Exports) {
if (E.ForwardTo.empty())
std::vector<Chunk *> forwards;
for (Export &e : config->exports) {
if (e.forwardTo.empty())
continue;
E.ForwardChunk = make<StringChunk>(E.ForwardTo);
Forwards.push_back(E.ForwardChunk);
e.forwardChunk = make<StringChunk>(e.forwardTo);
forwards.push_back(e.forwardChunk);
}
auto *NameTab = make<NamePointersChunk>(Names);
auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
AddressTab, NameTab, OrdinalTab);
Chunks.push_back(Dir);
Chunks.push_back(DLLName);
Chunks.push_back(AddressTab);
Chunks.push_back(NameTab);
Chunks.push_back(OrdinalTab);
Chunks.insert(Chunks.end(), Names.begin(), Names.end());
Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
auto *nameTab = make<NamePointersChunk>(names);
auto *ordinalTab = make<ExportOrdinalChunk>(names.size());
auto *dir = make<ExportDirectoryChunk>(maxOrdinal, names.size(), dllName,
addressTab, nameTab, ordinalTab);
chunks.push_back(dir);
chunks.push_back(dllName);
chunks.push_back(addressTab);
chunks.push_back(nameTab);
chunks.push_back(ordinalTab);
chunks.insert(chunks.end(), names.begin(), names.end());
chunks.insert(chunks.end(), forwards.begin(), forwards.end());
}
} // namespace coff

View File

@ -21,45 +21,45 @@ namespace coff {
// call create() to populate the chunk vectors.
class IdataContents {
public:
void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
bool empty() { return Imports.empty(); }
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
void create();
std::vector<DefinedImportData *> Imports;
std::vector<Chunk *> Dirs;
std::vector<Chunk *> Lookups;
std::vector<Chunk *> Addresses;
std::vector<Chunk *> Hints;
std::vector<Chunk *> DLLNames;
std::vector<DefinedImportData *> imports;
std::vector<Chunk *> dirs;
std::vector<Chunk *> lookups;
std::vector<Chunk *> addresses;
std::vector<Chunk *> hints;
std::vector<Chunk *> dllNames;
};
// Windows-specific.
// DelayLoadContents creates all chunks for the delay-load DLL import table.
class DelayLoadContents {
public:
void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
bool empty() { return Imports.empty(); }
void create(Defined *Helper);
void add(DefinedImportData *sym) { imports.push_back(sym); }
bool empty() { return imports.empty(); }
void create(Defined *helper);
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
ArrayRef<Chunk *> getCodeChunks() { return Thunks; }
ArrayRef<Chunk *> getCodeChunks() { return thunks; }
uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
uint64_t getDirRVA() { return dirs[0]->getRVA(); }
uint64_t getDirSize();
private:
Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
Chunk *newThunkChunk(DefinedImportData *s, Chunk *dir);
Defined *Helper;
std::vector<DefinedImportData *> Imports;
std::vector<Chunk *> Dirs;
std::vector<Chunk *> ModuleHandles;
std::vector<Chunk *> Addresses;
std::vector<Chunk *> Names;
std::vector<Chunk *> HintNames;
std::vector<Chunk *> Thunks;
std::vector<Chunk *> DLLNames;
Defined *helper;
std::vector<DefinedImportData *> imports;
std::vector<Chunk *> dirs;
std::vector<Chunk *> moduleHandles;
std::vector<Chunk *> addresses;
std::vector<Chunk *> names;
std::vector<Chunk *> hintNames;
std::vector<Chunk *> thunks;
std::vector<Chunk *> dllNames;
};
// Windows-specific.
@ -67,11 +67,11 @@ private:
class EdataContents {
public:
EdataContents();
std::vector<Chunk *> Chunks;
std::vector<Chunk *> chunks;
uint64_t getRVA() { return Chunks[0]->getRVA(); }
uint64_t getRVA() { return chunks[0]->getRVA(); }
uint64_t getSize() {
return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
return chunks.back()->getRVA() + chunks.back()->getSize() - getRVA();
}
};

View File

@ -32,40 +32,40 @@ namespace {
// before any dependent OBJ.
class TypeServerSource : public TpiSource {
public:
explicit TypeServerSource(MemoryBufferRef M, llvm::pdb::NativeSession *S)
: TpiSource(PDB, nullptr), Session(S), MB(M) {}
explicit TypeServerSource(MemoryBufferRef m, llvm::pdb::NativeSession *s)
: TpiSource(PDB, nullptr), session(s), mb(m) {}
// Queue a PDB type server for loading in the COFF Driver
static void enqueue(const ObjFile *DependentFile,
const TypeServer2Record &TS);
static void enqueue(const ObjFile *dependentFile,
const TypeServer2Record &ts);
// Create an instance
static Expected<TypeServerSource *> getInstance(MemoryBufferRef M);
static Expected<TypeServerSource *> getInstance(MemoryBufferRef m);
// Fetch the PDB instance loaded for a corresponding dependent OBJ.
static Expected<TypeServerSource *>
findFromFile(const ObjFile *DependentFile);
findFromFile(const ObjFile *dependentFile);
static std::map<std::string, std::pair<std::string, TypeServerSource *>>
Instances;
instances;
// The interface to the PDB (if it was opened successfully)
std::unique_ptr<llvm::pdb::NativeSession> Session;
std::unique_ptr<llvm::pdb::NativeSession> session;
private:
MemoryBufferRef MB;
MemoryBufferRef mb;
};
// This class represents the debug type stream of an OBJ file that depends on a
// PDB type server (see TypeServerSource).
class UseTypeServerSource : public TpiSource {
public:
UseTypeServerSource(const ObjFile *F, const TypeServer2Record *TS)
: TpiSource(UsingPDB, F), TypeServerDependency(*TS) {}
UseTypeServerSource(const ObjFile *f, const TypeServer2Record *ts)
: TpiSource(UsingPDB, f), typeServerDependency(*ts) {}
// Information about the PDB type server dependency, that needs to be loaded
// in before merging this OBJ.
TypeServer2Record TypeServerDependency;
TypeServer2Record typeServerDependency;
};
// This class represents the debug type stream of a Microsoft precompiled
@ -74,76 +74,76 @@ public:
// such files, clang does not.
class PrecompSource : public TpiSource {
public:
PrecompSource(const ObjFile *F) : TpiSource(PCH, F) {}
PrecompSource(const ObjFile *f) : TpiSource(PCH, f) {}
};
// This class represents the debug type stream of an OBJ file that depends on a
// Microsoft precompiled headers OBJ (see PrecompSource).
class UsePrecompSource : public TpiSource {
public:
UsePrecompSource(const ObjFile *F, const PrecompRecord *Precomp)
: TpiSource(UsingPCH, F), PrecompDependency(*Precomp) {}
UsePrecompSource(const ObjFile *f, const PrecompRecord *precomp)
: TpiSource(UsingPCH, f), precompDependency(*precomp) {}
// Information about the Precomp OBJ dependency, that needs to be loaded in
// before merging this OBJ.
PrecompRecord PrecompDependency;
PrecompRecord precompDependency;
};
} // namespace
static std::vector<std::unique_ptr<TpiSource>> GC;
TpiSource::TpiSource(TpiKind K, const ObjFile *F) : Kind(K), File(F) {
TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) {
GC.push_back(std::unique_ptr<TpiSource>(this));
}
TpiSource *lld::coff::makeTpiSource(const ObjFile *F) {
return new TpiSource(TpiSource::Regular, F);
TpiSource *lld::coff::makeTpiSource(const ObjFile *f) {
return new TpiSource(TpiSource::Regular, f);
}
TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *F,
const TypeServer2Record *TS) {
TypeServerSource::enqueue(F, *TS);
return new UseTypeServerSource(F, TS);
TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f,
const TypeServer2Record *ts) {
TypeServerSource::enqueue(f, *ts);
return new UseTypeServerSource(f, ts);
}
TpiSource *lld::coff::makePrecompSource(const ObjFile *F) {
return new PrecompSource(F);
TpiSource *lld::coff::makePrecompSource(const ObjFile *f) {
return new PrecompSource(f);
}
TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *F,
const PrecompRecord *Precomp) {
return new UsePrecompSource(F, Precomp);
TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f,
const PrecompRecord *precomp) {
return new UsePrecompSource(f, precomp);
}
namespace lld {
namespace coff {
template <>
const PrecompRecord &retrieveDependencyInfo(const TpiSource *Source) {
assert(Source->Kind == TpiSource::UsingPCH);
return ((const UsePrecompSource *)Source)->PrecompDependency;
const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) {
assert(source->kind == TpiSource::UsingPCH);
return ((const UsePrecompSource *)source)->precompDependency;
}
template <>
const TypeServer2Record &retrieveDependencyInfo(const TpiSource *Source) {
assert(Source->Kind == TpiSource::UsingPDB);
return ((const UseTypeServerSource *)Source)->TypeServerDependency;
const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) {
assert(source->kind == TpiSource::UsingPDB);
return ((const UseTypeServerSource *)source)->typeServerDependency;
}
} // namespace coff
} // namespace lld
std::map<std::string, std::pair<std::string, TypeServerSource *>>
TypeServerSource::Instances;
TypeServerSource::instances;
// Make a PDB path assuming the PDB is in the same folder as the OBJ
static std::string getPdbBaseName(const ObjFile *File, StringRef TSPath) {
StringRef LocalPath =
!File->ParentName.empty() ? File->ParentName : File->getName();
SmallString<128> Path = sys::path::parent_path(LocalPath);
static std::string getPdbBaseName(const ObjFile *file, StringRef tSPath) {
StringRef localPath =
!file->parentName.empty() ? file->parentName : file->getName();
SmallString<128> path = sys::path::parent_path(localPath);
// Currently, type server PDBs are only created by MSVC cl, which only runs
// on Windows, so we can assume type server paths are Windows style.
sys::path::append(Path, sys::path::filename(TSPath, sys::path::Style::windows));
return Path.str();
sys::path::append(path, sys::path::filename(tSPath, sys::path::Style::windows));
return path.str();
}
// The casing of the PDB path stamped in the OBJ can differ from the actual path
@ -158,80 +158,80 @@ static std::string normalizePdbPath(StringRef path) {
}
// If existing, return the actual PDB path on disk.
static Optional<std::string> findPdbPath(StringRef PDBPath,
const ObjFile *DependentFile) {
static Optional<std::string> findPdbPath(StringRef pdbPath,
const ObjFile *dependentFile) {
// Ensure the file exists before anything else. In some cases, if the path
// points to a removable device, Driver::enqueuePath() would fail with an
// error (EAGAIN, "resource unavailable try again") which we want to skip
// silently.
if (llvm::sys::fs::exists(PDBPath))
return normalizePdbPath(PDBPath);
std::string Ret = getPdbBaseName(DependentFile, PDBPath);
if (llvm::sys::fs::exists(Ret))
return normalizePdbPath(Ret);
if (llvm::sys::fs::exists(pdbPath))
return normalizePdbPath(pdbPath);
std::string ret = getPdbBaseName(dependentFile, pdbPath);
if (llvm::sys::fs::exists(ret))
return normalizePdbPath(ret);
return None;
}
// Fetch the PDB instance that was already loaded by the COFF Driver.
Expected<TypeServerSource *>
TypeServerSource::findFromFile(const ObjFile *DependentFile) {
const TypeServer2Record &TS =
retrieveDependencyInfo<TypeServer2Record>(DependentFile->DebugTypesObj);
TypeServerSource::findFromFile(const ObjFile *dependentFile) {
const TypeServer2Record &ts =
retrieveDependencyInfo<TypeServer2Record>(dependentFile->debugTypesObj);
Optional<std::string> P = findPdbPath(TS.Name, DependentFile);
if (!P)
return createFileError(TS.Name, errorCodeToError(std::error_code(
Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
if (!p)
return createFileError(ts.Name, errorCodeToError(std::error_code(
ENOENT, std::generic_category())));
auto It = TypeServerSource::Instances.find(*P);
auto it = TypeServerSource::instances.find(*p);
// The PDB file exists on disk, at this point we expect it to have been
// inserted in the map by TypeServerSource::loadPDB()
assert(It != TypeServerSource::Instances.end());
assert(it != TypeServerSource::instances.end());
std::pair<std::string, TypeServerSource *> &PDB = It->second;
std::pair<std::string, TypeServerSource *> &pdb = it->second;
if (!PDB.second)
if (!pdb.second)
return createFileError(
*P, createStringError(inconvertibleErrorCode(), PDB.first.c_str()));
*p, createStringError(inconvertibleErrorCode(), pdb.first.c_str()));
pdb::PDBFile &PDBFile = (PDB.second)->Session->getPDBFile();
pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream());
pdb::PDBFile &pdbFile = (pdb.second)->session->getPDBFile();
pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream());
// Just because a file with a matching name was found doesn't mean it can be
// used. The GUID must match between the PDB header and the OBJ
// TypeServer2 record. The 'Age' is used by MSVC incremental compilation.
if (Info.getGuid() != TS.getGuid())
if (info.getGuid() != ts.getGuid())
return createFileError(
TS.Name,
ts.Name,
make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
return PDB.second;
return pdb.second;
}
// FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
// moved here.
Expected<llvm::pdb::NativeSession *>
lld::coff::findTypeServerSource(const ObjFile *F) {
Expected<TypeServerSource *> TS = TypeServerSource::findFromFile(F);
if (!TS)
return TS.takeError();
return TS.get()->Session.get();
lld::coff::findTypeServerSource(const ObjFile *f) {
Expected<TypeServerSource *> ts = TypeServerSource::findFromFile(f);
if (!ts)
return ts.takeError();
return ts.get()->session.get();
}
// Queue a PDB type server for loading in the COFF Driver
void TypeServerSource::enqueue(const ObjFile *DependentFile,
const TypeServer2Record &TS) {
void TypeServerSource::enqueue(const ObjFile *dependentFile,
const TypeServer2Record &ts) {
// Start by finding where the PDB is located (either the record path or next
// to the OBJ file)
Optional<std::string> P = findPdbPath(TS.Name, DependentFile);
if (!P)
Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
if (!p)
return;
auto It = TypeServerSource::Instances.emplace(
*P, std::pair<std::string, TypeServerSource *>{});
if (!It.second)
auto it = TypeServerSource::instances.emplace(
*p, std::pair<std::string, TypeServerSource *>{});
if (!it.second)
return; // another OBJ already scheduled this PDB for load
Driver->enqueuePath(*P, false);
driver->enqueuePath(*p, false);
}
// Create an instance of TypeServerSource or an error string if the PDB couldn't
@ -239,30 +239,30 @@ void TypeServerSource::enqueue(const ObjFile *DependentFile,
// will be merged in. NOTE - a PDB load failure is not a link error: some
// debug info will simply be missing from the final PDB - that is the default
// accepted behavior.
void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef M) {
std::string Path = normalizePdbPath(M.getBufferIdentifier());
void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) {
std::string path = normalizePdbPath(m.getBufferIdentifier());
Expected<TypeServerSource *> TS = TypeServerSource::getInstance(M);
if (!TS)
TypeServerSource::Instances[Path] = {toString(TS.takeError()), nullptr};
Expected<TypeServerSource *> ts = TypeServerSource::getInstance(m);
if (!ts)
TypeServerSource::instances[path] = {toString(ts.takeError()), nullptr};
else
TypeServerSource::Instances[Path] = {{}, *TS};
TypeServerSource::instances[path] = {{}, *ts};
}
Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef M) {
std::unique_ptr<llvm::pdb::IPDBSession> ISession;
Error Err = pdb::NativeSession::createFromPdb(
MemoryBuffer::getMemBuffer(M, false), ISession);
if (Err)
return std::move(Err);
Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef m) {
std::unique_ptr<llvm::pdb::IPDBSession> iSession;
Error err = pdb::NativeSession::createFromPdb(
MemoryBuffer::getMemBuffer(m, false), iSession);
if (err)
return std::move(err);
std::unique_ptr<llvm::pdb::NativeSession> Session(
static_cast<pdb::NativeSession *>(ISession.release()));
std::unique_ptr<llvm::pdb::NativeSession> session(
static_cast<pdb::NativeSession *>(iSession.release()));
pdb::PDBFile &PDBFile = Session->getPDBFile();
Expected<pdb::InfoStream &> Info = PDBFile.getPDBInfoStream();
pdb::PDBFile &pdbFile = session->getPDBFile();
Expected<pdb::InfoStream &> info = pdbFile.getPDBInfoStream();
// All PDB Files should have an Info stream.
if (!Info)
return Info.takeError();
return new TypeServerSource(M, Session.release());
if (!info)
return info.takeError();
return new TypeServerSource(m, session.release());
}

View File

@ -31,28 +31,28 @@ class TpiSource {
public:
enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB };
TpiSource(TpiKind K, const ObjFile *F);
TpiSource(TpiKind k, const ObjFile *f);
virtual ~TpiSource() {}
const TpiKind Kind;
const ObjFile *File;
const TpiKind kind;
const ObjFile *file;
};
TpiSource *makeTpiSource(const ObjFile *F);
TpiSource *makeUseTypeServerSource(const ObjFile *F,
const llvm::codeview::TypeServer2Record *TS);
TpiSource *makePrecompSource(const ObjFile *F);
TpiSource *makeUsePrecompSource(const ObjFile *F,
const llvm::codeview::PrecompRecord *Precomp);
TpiSource *makeTpiSource(const ObjFile *f);
TpiSource *makeUseTypeServerSource(const ObjFile *f,
const llvm::codeview::TypeServer2Record *ts);
TpiSource *makePrecompSource(const ObjFile *f);
TpiSource *makeUsePrecompSource(const ObjFile *f,
const llvm::codeview::PrecompRecord *precomp);
void loadTypeServerSource(llvm::MemoryBufferRef M);
void loadTypeServerSource(llvm::MemoryBufferRef m);
// Temporary interface to get the dependency
template <typename T> const T &retrieveDependencyInfo(const TpiSource *Source);
template <typename T> const T &retrieveDependencyInfo(const TpiSource *source);
// Temporary interface until we move PDBLinker::maybeMergeTypeServerPDB here
llvm::Expected<llvm::pdb::NativeSession *>
findTypeServerSource(const ObjFile *F);
findTypeServerSource(const ObjFile *f);
} // namespace coff
} // namespace lld

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@ namespace lld {
namespace coff {
class LinkerDriver;
extern LinkerDriver *Driver;
extern LinkerDriver *driver;
using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
@ -44,71 +44,71 @@ public:
class ArgParser {
public:
// Concatenate LINK environment variable and given arguments and parse them.
llvm::opt::InputArgList parseLINK(std::vector<const char *> Args);
llvm::opt::InputArgList parseLINK(std::vector<const char *> args);
// Tokenizes a given string and then parses as command line options.
llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); }
// Tokenizes a given string and then parses as command line options in
// .drectve section. /EXPORT options are returned in second element
// to be processed in fastpath.
std::pair<llvm::opt::InputArgList, std::vector<StringRef>>
parseDirectives(StringRef S);
parseDirectives(StringRef s);
private:
// Parses command line options.
llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args);
std::vector<const char *> tokenize(StringRef S);
std::vector<const char *> tokenize(StringRef s);
COFFOptTable Table;
COFFOptTable table;
};
class LinkerDriver {
public:
void link(llvm::ArrayRef<const char *> Args);
void link(llvm::ArrayRef<const char *> args);
// Used by the resolver to parse .drectve section contents.
void parseDirectives(InputFile *File);
void parseDirectives(InputFile *file);
// Used by ArchiveFile to enqueue members.
void enqueueArchiveMember(const Archive::Child &C, StringRef SymName,
StringRef ParentName);
void enqueueArchiveMember(const Archive::Child &c, StringRef symName,
StringRef parentName);
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
void enqueuePath(StringRef Path, bool WholeArchive);
void enqueuePath(StringRef path, bool wholeArchive);
private:
std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro
std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
// Opens a file. Path has to be resolved already.
MemoryBufferRef openFile(StringRef Path);
MemoryBufferRef openFile(StringRef path);
// Searches a file from search paths.
Optional<StringRef> findFile(StringRef Filename);
Optional<StringRef> findLib(StringRef Filename);
StringRef doFindFile(StringRef Filename);
StringRef doFindLib(StringRef Filename);
StringRef doFindLibMinGW(StringRef Filename);
Optional<StringRef> findFile(StringRef filename);
Optional<StringRef> findLib(StringRef filename);
StringRef doFindFile(StringRef filename);
StringRef doFindLib(StringRef filename);
StringRef doFindLibMinGW(StringRef filename);
// Parses LIB environment which contains a list of search paths.
void addLibSearchPaths();
// Library search path. The first element is always "" (current directory).
std::vector<StringRef> SearchPaths;
std::vector<StringRef> searchPaths;
void maybeExportMinGWSymbols(const llvm::opt::InputArgList &Args);
void maybeExportMinGWSymbols(const llvm::opt::InputArgList &args);
// We don't want to add the same file more than once.
// Files are uniquified by their filesystem and file number.
std::set<llvm::sys::fs::UniqueID> VisitedFiles;
std::set<llvm::sys::fs::UniqueID> visitedFiles;
std::set<std::string> VisitedLibs;
std::set<std::string> visitedLibs;
Symbol *addUndefined(StringRef Sym);
Symbol *addUndefined(StringRef sym);
StringRef mangleMaybe(Symbol *S);
StringRef mangleMaybe(Symbol *s);
// Windows specific -- "main" is not the only main function in Windows.
// You can choose one from these four -- {w,}{WinMain,main}.
@ -120,36 +120,36 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
void addBuffer(std::unique_ptr<MemoryBuffer> MB, bool WholeArchive);
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
StringRef ParentName, uint64_t OffsetInArchive);
void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
StringRef parentName, uint64_t offsetInArchive);
void enqueueTask(std::function<void()> Task);
void enqueueTask(std::function<void()> task);
bool run();
std::list<std::function<void()>> TaskQueue;
std::vector<StringRef> FilePaths;
std::vector<MemoryBufferRef> Resources;
std::list<std::function<void()>> taskQueue;
std::vector<StringRef> filePaths;
std::vector<MemoryBufferRef> resources;
llvm::StringSet<> DirectivesExports;
llvm::StringSet<> directivesExports;
};
// Functions below this line are defined in DriverUtils.cpp.
void printHelp(const char *Argv0);
void printHelp(const char *argv0);
// Parses a string in the form of "<integer>[,<integer>]".
void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr);
void parseGuard(StringRef Arg);
void parseGuard(StringRef arg);
// Parses a string in the form of "<integer>[.<integer>]".
// Minor's default value is 0.
void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor);
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
uint32_t *Minor);
void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
uint32_t *minor);
void parseAlternateName(StringRef);
void parseMerge(StringRef);
@ -157,23 +157,23 @@ void parseSection(StringRef);
void parseAligncomm(StringRef);
// Parses a string in the form of "[:<integer>]"
void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine);
void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine);
// Parses a string in the form of "EMBED[,=<integer>]|NO".
void parseManifest(StringRef Arg);
void parseManifest(StringRef arg);
// Parses a string in the form of "level=<string>|uiAccess=<string>"
void parseManifestUAC(StringRef Arg);
void parseManifestUAC(StringRef arg);
// Parses a string in the form of "cd|net[,(cd|net)]*"
void parseSwaprun(StringRef Arg);
void parseSwaprun(StringRef arg);
// Create a resource file containing a manifest XML.
std::unique_ptr<MemoryBuffer> createManifestRes();
void createSideBySideManifest();
// Used for dllexported symbols.
Export parseExport(StringRef Arg);
Export parseExport(StringRef arg);
void fixupExports();
void assignExportOrdinals();
@ -181,12 +181,12 @@ void assignExportOrdinals();
// if value matches previous values for the key.
// This feature used in the directive section to reject
// incompatible objects.
void checkFailIfMismatch(StringRef Arg, InputFile *Source);
void checkFailIfMismatch(StringRef arg, InputFile *source);
// Convert Windows resource files (.res files) to a .obj file.
MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs);
MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs);
void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
void runMSVCLinker(std::string rsp, ArrayRef<StringRef> objects);
// Create enum with OPT_xxx values for each option in Options.td
enum {

File diff suppressed because it is too large Load Diff

View File

@ -37,32 +37,32 @@ using namespace llvm;
namespace lld {
namespace coff {
static Timer ICFTimer("ICF", Timer::root());
static Timer icfTimer("ICF", Timer::root());
class ICF {
public:
void run(ArrayRef<Chunk *> V);
void run(ArrayRef<Chunk *> v);
private:
void segregate(size_t Begin, size_t End, bool Constant);
void segregate(size_t begin, size_t end, bool constant);
bool assocEquals(const SectionChunk *A, const SectionChunk *B);
bool assocEquals(const SectionChunk *a, const SectionChunk *b);
bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
bool equalsConstant(const SectionChunk *a, const SectionChunk *b);
bool equalsVariable(const SectionChunk *a, const SectionChunk *b);
bool isEligible(SectionChunk *C);
bool isEligible(SectionChunk *c);
size_t findBoundary(size_t Begin, size_t End);
size_t findBoundary(size_t begin, size_t end);
void forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn);
void forEachClassRange(size_t begin, size_t end,
std::function<void(size_t, size_t)> fn);
void forEachClass(std::function<void(size_t, size_t)> Fn);
void forEachClass(std::function<void(size_t, size_t)> fn);
std::vector<SectionChunk *> Chunks;
int Cnt = 0;
std::atomic<bool> Repeat = {false};
std::vector<SectionChunk *> chunks;
int cnt = 0;
std::atomic<bool> repeat = {false};
};
// Returns true if section S is subject of ICF.
@ -76,144 +76,144 @@ private:
// merge read-only sections in a couple of cases where the address of the
// section is insignificant to the user program and the behaviour matches that
// of the Visual C++ linker.
bool ICF::isEligible(SectionChunk *C) {
bool ICF::isEligible(SectionChunk *c) {
// Non-comdat chunks, dead chunks, and writable chunks are not elegible.
bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
if (!C->isCOMDAT() || !C->Live || Writable)
bool writable = c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
if (!c->isCOMDAT() || !c->live || writable)
return false;
// Code sections are eligible.
if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
if (c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
return true;
// .pdata and .xdata unwind info sections are eligible.
StringRef OutSecName = C->getSectionName().split('$').first;
if (OutSecName == ".pdata" || OutSecName == ".xdata")
StringRef outSecName = c->getSectionName().split('$').first;
if (outSecName == ".pdata" || outSecName == ".xdata")
return true;
// So are vtables.
if (C->Sym && C->Sym->getName().startswith("??_7"))
if (c->sym && c->sym->getName().startswith("??_7"))
return true;
// Anything else not in an address-significance table is eligible.
return !C->KeepUnique;
return !c->keepUnique;
}
// Split an equivalence class into smaller classes.
void ICF::segregate(size_t Begin, size_t End, bool Constant) {
while (Begin < End) {
void ICF::segregate(size_t begin, size_t end, bool constant) {
while (begin < end) {
// Divide [Begin, End) into two. Let Mid be the start index of the
// second group.
auto Bound = std::stable_partition(
Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) {
if (Constant)
return equalsConstant(Chunks[Begin], S);
return equalsVariable(Chunks[Begin], S);
auto bound = std::stable_partition(
chunks.begin() + begin + 1, chunks.begin() + end, [&](SectionChunk *s) {
if (constant)
return equalsConstant(chunks[begin], s);
return equalsVariable(chunks[begin], s);
});
size_t Mid = Bound - Chunks.begin();
size_t mid = bound - chunks.begin();
// Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
// equivalence class ID because every group ends with a unique index.
for (size_t I = Begin; I < Mid; ++I)
Chunks[I]->Class[(Cnt + 1) % 2] = Mid;
for (size_t i = begin; i < mid; ++i)
chunks[i]->eqClass[(cnt + 1) % 2] = mid;
// If we created a group, we need to iterate the main loop again.
if (Mid != End)
Repeat = true;
if (mid != end)
repeat = true;
Begin = Mid;
begin = mid;
}
}
// Returns true if two sections' associative children are equal.
bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
auto ChildClasses = [&](const SectionChunk *SC) {
std::vector<uint32_t> Classes;
for (const SectionChunk &C : SC->children())
if (!C.getSectionName().startswith(".debug") &&
C.getSectionName() != ".gfids$y" && C.getSectionName() != ".gljmp$y")
Classes.push_back(C.Class[Cnt % 2]);
return Classes;
bool ICF::assocEquals(const SectionChunk *a, const SectionChunk *b) {
auto childClasses = [&](const SectionChunk *sc) {
std::vector<uint32_t> classes;
for (const SectionChunk &c : sc->children())
if (!c.getSectionName().startswith(".debug") &&
c.getSectionName() != ".gfids$y" && c.getSectionName() != ".gljmp$y")
classes.push_back(c.eqClass[cnt % 2]);
return classes;
};
return ChildClasses(A) == ChildClasses(B);
return childClasses(a) == childClasses(b);
}
// Compare "non-moving" part of two sections, namely everything
// except relocation targets.
bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
if (A->RelocsSize != B->RelocsSize)
bool ICF::equalsConstant(const SectionChunk *a, const SectionChunk *b) {
if (a->relocsSize != b->relocsSize)
return false;
// Compare relocations.
auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
if (R1.Type != R2.Type ||
R1.VirtualAddress != R2.VirtualAddress) {
auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) {
if (r1.Type != r2.Type ||
r1.VirtualAddress != r2.VirtualAddress) {
return false;
}
Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex);
Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex);
if (B1 == B2)
Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex);
Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex);
if (b1 == b2)
return true;
if (auto *D1 = dyn_cast<DefinedRegular>(B1))
if (auto *D2 = dyn_cast<DefinedRegular>(B2))
return D1->getValue() == D2->getValue() &&
D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
if (auto *d1 = dyn_cast<DefinedRegular>(b1))
if (auto *d2 = dyn_cast<DefinedRegular>(b2))
return d1->getValue() == d2->getValue() &&
d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2];
return false;
};
if (!std::equal(A->getRelocs().begin(), A->getRelocs().end(),
B->getRelocs().begin(), Eq))
if (!std::equal(a->getRelocs().begin(), a->getRelocs().end(),
b->getRelocs().begin(), eq))
return false;
// Compare section attributes and contents.
return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
A->getSectionName() == B->getSectionName() &&
A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
assocEquals(A, B);
return a->getOutputCharacteristics() == b->getOutputCharacteristics() &&
a->getSectionName() == b->getSectionName() &&
a->header->SizeOfRawData == b->header->SizeOfRawData &&
a->checksum == b->checksum && a->getContents() == b->getContents() &&
assocEquals(a, b);
}
// Compare "moving" part of two sections, namely relocation targets.
bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
bool ICF::equalsVariable(const SectionChunk *a, const SectionChunk *b) {
// Compare relocations.
auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex);
Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex);
if (B1 == B2)
auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) {
Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex);
Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex);
if (b1 == b2)
return true;
if (auto *D1 = dyn_cast<DefinedRegular>(B1))
if (auto *D2 = dyn_cast<DefinedRegular>(B2))
return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
if (auto *d1 = dyn_cast<DefinedRegular>(b1))
if (auto *d2 = dyn_cast<DefinedRegular>(b2))
return d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2];
return false;
};
return std::equal(A->getRelocs().begin(), A->getRelocs().end(),
B->getRelocs().begin(), Eq) &&
assocEquals(A, B);
return std::equal(a->getRelocs().begin(), a->getRelocs().end(),
b->getRelocs().begin(), eq) &&
assocEquals(a, b);
}
// Find the first Chunk after Begin that has a different class from Begin.
size_t ICF::findBoundary(size_t Begin, size_t End) {
for (size_t I = Begin + 1; I < End; ++I)
if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
return I;
return End;
size_t ICF::findBoundary(size_t begin, size_t end) {
for (size_t i = begin + 1; i < end; ++i)
if (chunks[begin]->eqClass[cnt % 2] != chunks[i]->eqClass[cnt % 2])
return i;
return end;
}
void ICF::forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn) {
while (Begin < End) {
size_t Mid = findBoundary(Begin, End);
Fn(Begin, Mid);
Begin = Mid;
void ICF::forEachClassRange(size_t begin, size_t end,
std::function<void(size_t, size_t)> fn) {
while (begin < end) {
size_t mid = findBoundary(begin, end);
fn(begin, mid);
begin = mid;
}
}
// Call Fn on each class group.
void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
void ICF::forEachClass(std::function<void(size_t, size_t)> fn) {
// If the number of sections are too small to use threading,
// call Fn sequentially.
if (Chunks.size() < 1024) {
forEachClassRange(0, Chunks.size(), Fn);
++Cnt;
if (chunks.size() < 1024) {
forEachClassRange(0, chunks.size(), fn);
++cnt;
return;
}
@ -221,97 +221,97 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// The sharding must be completed before any calls to Fn are made
// so that Fn can modify the Chunks in its shard without causing data
// races.
const size_t NumShards = 256;
size_t Step = Chunks.size() / NumShards;
size_t Boundaries[NumShards + 1];
Boundaries[0] = 0;
Boundaries[NumShards] = Chunks.size();
parallelForEachN(1, NumShards, [&](size_t I) {
Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size());
const size_t numShards = 256;
size_t step = chunks.size() / numShards;
size_t boundaries[numShards + 1];
boundaries[0] = 0;
boundaries[numShards] = chunks.size();
parallelForEachN(1, numShards, [&](size_t i) {
boundaries[i] = findBoundary((i - 1) * step, chunks.size());
});
parallelForEachN(1, NumShards + 1, [&](size_t I) {
if (Boundaries[I - 1] < Boundaries[I]) {
forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
parallelForEachN(1, numShards + 1, [&](size_t i) {
if (boundaries[i - 1] < boundaries[i]) {
forEachClassRange(boundaries[i - 1], boundaries[i], fn);
}
});
++Cnt;
++cnt;
}
// Merge identical COMDAT sections.
// Two sections are considered the same if their section headers,
// contents and relocations are all the same.
void ICF::run(ArrayRef<Chunk *> Vec) {
ScopedTimer T(ICFTimer);
void ICF::run(ArrayRef<Chunk *> vec) {
ScopedTimer t(icfTimer);
// Collect only mergeable sections and group by hash value.
uint32_t NextId = 1;
for (Chunk *C : Vec) {
if (auto *SC = dyn_cast<SectionChunk>(C)) {
if (isEligible(SC))
Chunks.push_back(SC);
uint32_t nextId = 1;
for (Chunk *c : vec) {
if (auto *sc = dyn_cast<SectionChunk>(c)) {
if (isEligible(sc))
chunks.push_back(sc);
else
SC->Class[0] = NextId++;
sc->eqClass[0] = nextId++;
}
}
// Make sure that ICF doesn't merge sections that are being handled by string
// tail merging.
for (MergeChunk *MC : MergeChunk::Instances)
if (MC)
for (SectionChunk *SC : MC->Sections)
SC->Class[0] = NextId++;
for (MergeChunk *mc : MergeChunk::instances)
if (mc)
for (SectionChunk *sc : mc->sections)
sc->eqClass[0] = nextId++;
// Initially, we use hash values to partition sections.
parallelForEach(Chunks, [&](SectionChunk *SC) {
SC->Class[0] = xxHash64(SC->getContents());
parallelForEach(chunks, [&](SectionChunk *sc) {
sc->eqClass[0] = xxHash64(sc->getContents());
});
// Combine the hashes of the sections referenced by each section into its
// hash.
for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
parallelForEach(Chunks, [&](SectionChunk *SC) {
uint32_t Hash = SC->Class[Cnt % 2];
for (Symbol *B : SC->symbols())
if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
Hash += Sym->getChunk()->Class[Cnt % 2];
for (unsigned cnt = 0; cnt != 2; ++cnt) {
parallelForEach(chunks, [&](SectionChunk *sc) {
uint32_t hash = sc->eqClass[cnt % 2];
for (Symbol *b : sc->symbols())
if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
hash += sym->getChunk()->eqClass[cnt % 2];
// Set MSB to 1 to avoid collisions with non-hash classs.
SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
sc->eqClass[(cnt + 1) % 2] = hash | (1U << 31);
});
}
// From now on, sections in Chunks are ordered so that sections in
// the same group are consecutive in the vector.
llvm::stable_sort(Chunks, [](const SectionChunk *A, const SectionChunk *B) {
return A->Class[0] < B->Class[0];
llvm::stable_sort(chunks, [](const SectionChunk *a, const SectionChunk *b) {
return a->eqClass[0] < b->eqClass[0];
});
// Compare static contents and assign unique IDs for each static content.
forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); });
// Split groups by comparing relocations until convergence is obtained.
do {
Repeat = false;
repeat = false;
forEachClass(
[&](size_t Begin, size_t End) { segregate(Begin, End, false); });
} while (Repeat);
[&](size_t begin, size_t end) { segregate(begin, end, false); });
} while (repeat);
log("ICF needed " + Twine(Cnt) + " iterations");
log("ICF needed " + Twine(cnt) + " iterations");
// Merge sections in the same classs.
forEachClass([&](size_t Begin, size_t End) {
if (End - Begin == 1)
forEachClass([&](size_t begin, size_t end) {
if (end - begin == 1)
return;
log("Selected " + Chunks[Begin]->getDebugName());
for (size_t I = Begin + 1; I < End; ++I) {
log(" Removed " + Chunks[I]->getDebugName());
Chunks[Begin]->replace(Chunks[I]);
log("Selected " + chunks[begin]->getDebugName());
for (size_t i = begin + 1; i < end; ++i) {
log(" Removed " + chunks[i]->getDebugName());
chunks[begin]->replace(chunks[i]);
}
});
}
// Entry point to ICF.
void doICF(ArrayRef<Chunk *> Chunks) { ICF().run(Chunks); }
void doICF(ArrayRef<Chunk *> chunks) { ICF().run(chunks); }
} // namespace coff
} // namespace lld

View File

@ -17,7 +17,7 @@ namespace coff {
class Chunk;
void doICF(ArrayRef<Chunk *> Chunks);
void doICF(ArrayRef<Chunk *> chunks);
} // namespace coff
} // namespace lld

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@ class DbiModuleDescriptorBuilder;
namespace lld {
namespace coff {
std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *File);
std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *file);
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
using llvm::COFF::MachineTypes;
@ -57,11 +57,11 @@ class TpiSource;
class InputFile {
public:
enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
Kind kind() const { return FileKind; }
Kind kind() const { return fileKind; }
virtual ~InputFile() {}
// Returns the filename.
StringRef getName() const { return MB.getBufferIdentifier(); }
StringRef getName() const { return mb.getBufferIdentifier(); }
// Reads a file (the constructor doesn't do that).
virtual void parse() = 0;
@ -69,118 +69,118 @@ public:
// Returns the CPU type this file was compiled to.
virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
MemoryBufferRef MB;
MemoryBufferRef mb;
// An archive file name if this file is created from an archive.
StringRef ParentName;
StringRef parentName;
// Returns .drectve section contents if exist.
StringRef getDirectives() { return Directives; }
StringRef getDirectives() { return directives; }
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}
StringRef Directives;
StringRef directives;
private:
const Kind FileKind;
const Kind fileKind;
};
// .lib or .a file.
class ArchiveFile : public InputFile {
public:
explicit ArchiveFile(MemoryBufferRef M);
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
explicit ArchiveFile(MemoryBufferRef m);
static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
void parse() override;
// Enqueues an archive member load for the given symbol. If we've already
// enqueued a load for the same archive member, this function does nothing,
// which ensures that we don't load the same member more than once.
void addMember(const Archive::Symbol *Sym);
void addMember(const Archive::Symbol *sym);
private:
std::unique_ptr<Archive> File;
llvm::DenseSet<uint64_t> Seen;
std::unique_ptr<Archive> file;
llvm::DenseSet<uint64_t> seen;
};
// .obj or .o file. This may be a member of an archive file.
class ObjFile : public InputFile {
public:
explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
void parse() override;
MachineTypes getMachineType() override;
ArrayRef<Chunk *> getChunks() { return Chunks; }
ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; }
ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; }
ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; }
ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; }
ArrayRef<Symbol *> getSymbols() { return Symbols; }
ArrayRef<Chunk *> getChunks() { return chunks; }
ArrayRef<SectionChunk *> getDebugChunks() { return debugChunks; }
ArrayRef<SectionChunk *> getSXDataChunks() { return sXDataChunks; }
ArrayRef<SectionChunk *> getGuardFidChunks() { return guardFidChunks; }
ArrayRef<SectionChunk *> getGuardLJmpChunks() { return guardLJmpChunks; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
ArrayRef<uint8_t> getDebugSection(StringRef SecName);
ArrayRef<uint8_t> getDebugSection(StringRef secName);
// Returns a Symbol object for the SymbolIndex'th symbol in the
// underlying object file.
Symbol *getSymbol(uint32_t SymbolIndex) {
return Symbols[SymbolIndex];
Symbol *getSymbol(uint32_t symbolIndex) {
return symbols[symbolIndex];
}
// Returns the underlying COFF file.
COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
COFFObjectFile *getCOFFObj() { return coffObj.get(); }
// Add a symbol for a range extension thunk. Return the new symbol table
// index. This index can be used to modify a relocation.
uint32_t addRangeThunkSymbol(Symbol *Thunk) {
Symbols.push_back(Thunk);
return Symbols.size() - 1;
uint32_t addRangeThunkSymbol(Symbol *thunk) {
symbols.push_back(thunk);
return symbols.size() - 1;
}
static std::vector<ObjFile *> Instances;
static std::vector<ObjFile *> instances;
// Flags in the absolute @feat.00 symbol if it is present. These usually
// indicate if an object was compiled with certain security features enabled
// like stack guard, safeseh, /guard:cf, or other things.
uint32_t Feat00Flags = 0;
uint32_t feat00Flags = 0;
// True if this object file is compatible with SEH. COFF-specific and
// x86-only. COFF spec 5.10.1. The .sxdata section.
bool hasSafeSEH() { return Feat00Flags & 0x1; }
bool hasSafeSEH() { return feat00Flags & 0x1; }
// True if this file was compiled with /guard:cf.
bool hasGuardCF() { return Feat00Flags & 0x800; }
bool hasGuardCF() { return feat00Flags & 0x800; }
// Pointer to the PDB module descriptor builder. Various debug info records
// will reference object files by "module index", which is here. Things like
// source files and section contributions are also recorded here. Will be null
// if we are not producing a PDB.
llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
llvm::pdb::DbiModuleDescriptorBuilder *moduleDBI = nullptr;
const coff_section *AddrsigSec = nullptr;
const coff_section *addrsigSec = nullptr;
// When using Microsoft precompiled headers, this is the PCH's key.
// The same key is used by both the precompiled object, and objects using the
// precompiled object. Any difference indicates out-of-date objects.
llvm::Optional<uint32_t> PCHSignature;
llvm::Optional<uint32_t> pchSignature;
// Whether this is an object file created from .res files.
bool IsResourceObjFile = false;
bool isResourceObjFile = false;
// Whether this file was compiled with /hotpatch.
bool HotPatchable = false;
bool hotPatchable = false;
// Whether the object was already merged into the final PDB.
bool MergedIntoPDB = false;
bool mergedIntoPDB = false;
// If the OBJ has a .debug$T stream, this tells how it will be handled.
TpiSource *DebugTypesObj = nullptr;
TpiSource *debugTypesObj = nullptr;
// The .debug$T stream if there's one.
llvm::Optional<llvm::codeview::CVTypeArray> DebugTypes;
llvm::Optional<llvm::codeview::CVTypeArray> debugTypes;
private:
const coff_section* getSection(uint32_t I);
const coff_section *getSection(COFFSymbolRef Sym) {
return getSection(Sym.getSectionNumber());
const coff_section* getSection(uint32_t i);
const coff_section *getSection(COFFSymbolRef sym) {
return getSection(sym.getSectionNumber());
}
void initializeChunks();
@ -189,26 +189,26 @@ private:
void initializeDependencies();
SectionChunk *
readSection(uint32_t SectionNumber,
const llvm::object::coff_aux_section_definition *Def,
StringRef LeaderName);
readSection(uint32_t sectionNumber,
const llvm::object::coff_aux_section_definition *def,
StringRef leaderName);
void readAssociativeDefinition(
COFFSymbolRef COFFSym,
const llvm::object::coff_aux_section_definition *Def);
COFFSymbolRef coffSym,
const llvm::object::coff_aux_section_definition *def);
void readAssociativeDefinition(
COFFSymbolRef COFFSym,
const llvm::object::coff_aux_section_definition *Def,
uint32_t ParentSection);
COFFSymbolRef coffSym,
const llvm::object::coff_aux_section_definition *def,
uint32_t parentSection);
void recordPrevailingSymbolForMingw(
COFFSymbolRef COFFSym,
llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
COFFSymbolRef coffSym,
llvm::DenseMap<StringRef, uint32_t> &prevailingSectionMap);
void maybeAssociateSEHForMingw(
COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def,
const llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
COFFSymbolRef sym, const llvm::object::coff_aux_section_definition *def,
const llvm::DenseMap<StringRef, uint32_t> &prevailingSectionMap);
// Given a new symbol Sym with comdat selection Selection, if the new
// symbol is not (yet) Prevailing and the existing comdat leader set to
@ -216,48 +216,48 @@ private:
// match the existing symbol and its selection. If either old or new
// symbol have selection IMAGE_COMDAT_SELECT_LARGEST, Sym might replace
// the existing leader. In that case, Prevailing is set to true.
void handleComdatSelection(COFFSymbolRef Sym,
llvm::COFF::COMDATType &Selection,
bool &Prevailing, DefinedRegular *Leader);
void handleComdatSelection(COFFSymbolRef sym,
llvm::COFF::COMDATType &selection,
bool &prevailing, DefinedRegular *leader);
llvm::Optional<Symbol *>
createDefined(COFFSymbolRef Sym,
createDefined(COFFSymbolRef sym,
std::vector<const llvm::object::coff_aux_section_definition *>
&ComdatDefs,
bool &PrevailingComdat);
Symbol *createRegular(COFFSymbolRef Sym);
Symbol *createUndefined(COFFSymbolRef Sym);
&comdatDefs,
bool &prevailingComdat);
Symbol *createRegular(COFFSymbolRef sym);
Symbol *createUndefined(COFFSymbolRef sym);
std::unique_ptr<COFFObjectFile> COFFObj;
std::unique_ptr<COFFObjectFile> coffObj;
// List of all chunks defined by this file. This includes both section
// chunks and non-section chunks for common symbols.
std::vector<Chunk *> Chunks;
std::vector<Chunk *> chunks;
// CodeView debug info sections.
std::vector<SectionChunk *> DebugChunks;
std::vector<SectionChunk *> debugChunks;
// Chunks containing symbol table indices of exception handlers. Only used for
// 32-bit x86.
std::vector<SectionChunk *> SXDataChunks;
std::vector<SectionChunk *> sXDataChunks;
// Chunks containing symbol table indices of address taken symbols and longjmp
// targets. These are not linked into the final binary when /guard:cf is set.
std::vector<SectionChunk *> GuardFidChunks;
std::vector<SectionChunk *> GuardLJmpChunks;
std::vector<SectionChunk *> guardFidChunks;
std::vector<SectionChunk *> guardLJmpChunks;
// This vector contains the same chunks as Chunks, but they are
// indexed such that you can get a SectionChunk by section index.
// Nonexistent section indices are filled with null pointers.
// (Because section number is 1-based, the first slot is always a
// null pointer.)
std::vector<SectionChunk *> SparseChunks;
std::vector<SectionChunk *> sparseChunks;
// This vector contains a list of all symbols defined or referenced by this
// file. They are indexed such that you can get a Symbol by symbol
// index. Nonexistent indices (which are occupied by auxiliary
// symbols in the real symbol table) are filled with null pointers.
std::vector<Symbol *> Symbols;
std::vector<Symbol *> symbols;
};
// This type represents import library members that contain DLL names
@ -265,23 +265,23 @@ private:
// for details about the format.
class ImportFile : public InputFile {
public:
explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {}
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
static bool classof(const InputFile *f) { return f->kind() == ImportKind; }
static std::vector<ImportFile *> Instances;
static std::vector<ImportFile *> instances;
Symbol *ImpSym = nullptr;
Symbol *ThunkSym = nullptr;
std::string DLLName;
Symbol *impSym = nullptr;
Symbol *thunkSym = nullptr;
std::string dllName;
private:
void parse() override;
public:
StringRef ExternalName;
const coff_import_header *Hdr;
Chunk *Location = nullptr;
StringRef externalName;
const coff_import_header *hdr;
Chunk *location = nullptr;
// We want to eliminate dllimported symbols if no one actually refers them.
// These "Live" bits are used to keep track of which import library members
@ -291,29 +291,29 @@ public:
// symbols provided by this import library member. We also track whether the
// imported symbol is used separately from whether the thunk is used in order
// to avoid creating unnecessary thunks.
bool Live = !Config->DoGC;
bool ThunkLive = !Config->DoGC;
bool live = !config->doGC;
bool thunkLive = !config->doGC;
};
// Used for LTO.
class BitcodeFile : public InputFile {
public:
BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive);
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
ArrayRef<Symbol *> getSymbols() { return Symbols; }
BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
MachineTypes getMachineType() override;
static std::vector<BitcodeFile *> Instances;
std::unique_ptr<llvm::lto::InputFile> Obj;
static std::vector<BitcodeFile *> instances;
std::unique_ptr<llvm::lto::InputFile> obj;
private:
void parse() override;
std::vector<Symbol *> Symbols;
std::vector<Symbol *> symbols;
};
} // namespace coff
std::string toString(const coff::InputFile *File);
std::string toString(const coff::InputFile *file);
} // namespace lld
#endif

View File

@ -42,112 +42,112 @@ using namespace lld;
using namespace lld::coff;
static std::unique_ptr<lto::LTO> createLTO() {
lto::Config C;
C.Options = initTargetOptionsFromCodeGenFlags();
lto::Config c;
c.Options = initTargetOptionsFromCodeGenFlags();
// Always emit a section per function/datum with LTO. LLVM LTO should get most
// of the benefit of linker GC, but there are still opportunities for ICF.
C.Options.FunctionSections = true;
C.Options.DataSections = true;
c.Options.FunctionSections = true;
c.Options.DataSections = true;
// Use static reloc model on 32-bit x86 because it usually results in more
// compact code, and because there are also known code generation bugs when
// using the PIC model (see PR34306).
if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386)
C.RelocModel = Reloc::Static;
if (config->machine == COFF::IMAGE_FILE_MACHINE_I386)
c.RelocModel = Reloc::Static;
else
C.RelocModel = Reloc::PIC_;
C.DisableVerify = true;
C.DiagHandler = diagnosticHandler;
C.OptLevel = Config->LTOO;
C.CPU = getCPUStr();
C.MAttrs = getMAttrs();
C.CGOptLevel = args::getCGOptLevel(Config->LTOO);
c.RelocModel = Reloc::PIC_;
c.DisableVerify = true;
c.DiagHandler = diagnosticHandler;
c.OptLevel = config->ltoo;
c.CPU = getCPUStr();
c.MAttrs = getMAttrs();
c.CGOptLevel = args::getCGOptLevel(config->ltoo);
if (Config->SaveTemps)
checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
if (config->saveTemps)
checkError(c.addSaveTemps(std::string(config->outputFile) + ".",
/*UseInputModulePath*/ true));
lto::ThinBackend Backend;
if (Config->ThinLTOJobs != 0)
Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
return llvm::make_unique<lto::LTO>(std::move(C), Backend,
Config->LTOPartitions);
lto::ThinBackend backend;
if (config->thinLTOJobs != 0)
backend = lto::createInProcessThinBackend(config->thinLTOJobs);
return llvm::make_unique<lto::LTO>(std::move(c), backend,
config->ltoPartitions);
}
BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::BitcodeCompiler() : ltoObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
static void undefine(Symbol *S) { replaceSymbol<Undefined>(S, S->getName()); }
static void undefine(Symbol *s) { replaceSymbol<Undefined>(s, s->getName()); }
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
std::vector<Symbol *> SymBodies = F.getSymbols();
std::vector<lto::SymbolResolution> Resols(SymBodies.size());
void BitcodeCompiler::add(BitcodeFile &f) {
lto::InputFile &obj = *f.obj;
unsigned symNum = 0;
std::vector<Symbol *> symBodies = f.getSymbols();
std::vector<lto::SymbolResolution> resols(symBodies.size());
// Provide a resolution to the LTO API for each symbol.
for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
Symbol *Sym = SymBodies[SymNum];
lto::SymbolResolution &R = Resols[SymNum];
++SymNum;
for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
Symbol *sym = symBodies[symNum];
lto::SymbolResolution &r = resols[symNum];
++symNum;
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
if (R.Prevailing)
undefine(Sym);
r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
r.VisibleToRegularObj = sym->isUsedInRegularObj;
if (r.Prevailing)
undefine(sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
checkError(ltoObj->add(std::move(f.obj), resols));
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
Buf.resize(MaxTasks);
Files.resize(MaxTasks);
unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks);
files.resize(maxTasks);
// The /lldltocache option specifies the path to a directory in which to cache
// native object files for ThinLTO incremental builds. If a path was
// specified, configure LTO to use it as the cache directory.
lto::NativeObjectCache Cache;
if (!Config->LTOCache.empty())
Cache = check(lto::localCache(
Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
Files[Task] = std::move(MB);
lto::NativeObjectCache cache;
if (!config->ltoCache.empty())
cache = check(lto::localCache(
config->ltoCache, [&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
checkError(LTOObj->run(
[&](size_t Task) {
checkError(ltoObj->run(
[&](size_t task) {
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<raw_svector_ostream>(Buf[Task]));
llvm::make_unique<raw_svector_ostream>(buf[task]));
},
Cache));
cache));
if (!Config->LTOCache.empty())
pruneCache(Config->LTOCache, Config->LTOCachePolicy);
if (!config->ltoCache.empty())
pruneCache(config->ltoCache, config->ltoCachePolicy);
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buf[I].empty())
std::vector<StringRef> ret;
for (unsigned i = 0; i != maxTasks; ++i) {
if (buf[i].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
saveBuffer(Buf[I], Config->OutputFile + ".lto.obj");
if (config->saveTemps) {
if (i == 0)
saveBuffer(buf[i], config->outputFile + ".lto.obj");
else
saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj");
saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.obj");
}
Ret.emplace_back(Buf[I].data(), Buf[I].size());
ret.emplace_back(buf[i].data(), buf[i].size());
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(File->getBuffer());
for (std::unique_ptr<MemoryBuffer> &file : files)
if (file)
ret.push_back(file->getBuffer());
return Ret;
return ret;
}

View File

@ -42,13 +42,13 @@ public:
BitcodeCompiler();
~BitcodeCompiler();
void add(BitcodeFile &F);
void add(BitcodeFile &f);
std::vector<StringRef> compile();
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
std::unique_ptr<llvm::lto::LTO> ltoObj;
std::vector<SmallString<0>> buf;
std::vector<std::unique_ptr<MemoryBuffer>> files;
};
}
}

View File

@ -35,90 +35,90 @@ using namespace lld::coff;
using SymbolMapTy =
DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>;
static const std::string Indent8 = " "; // 8 spaces
static const std::string Indent16 = " "; // 16 spaces
static const std::string indent8 = " "; // 8 spaces
static const std::string indent16 = " "; // 16 spaces
// Print out the first three columns of a line.
static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
uint64_t Align) {
OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
uint64_t align) {
os << format("%08llx %08llx %5lld ", addr, size, align);
}
// Returns a list of all symbols that we want to print out.
static std::vector<DefinedRegular *> getSymbols() {
std::vector<DefinedRegular *> V;
for (ObjFile *File : ObjFile::Instances)
for (Symbol *B : File->getSymbols())
if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
if (Sym && !Sym->getCOFFSymbol().isSectionDefinition())
V.push_back(Sym);
return V;
std::vector<DefinedRegular *> v;
for (ObjFile *file : ObjFile::instances)
for (Symbol *b : file->getSymbols())
if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
if (sym && !sym->getCOFFSymbol().isSectionDefinition())
v.push_back(sym);
return v;
}
// Returns a map from sections to their symbols.
static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
SymbolMapTy Ret;
for (DefinedRegular *S : Syms)
Ret[S->getChunk()].push_back(S);
static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) {
SymbolMapTy ret;
for (DefinedRegular *s : syms)
ret[s->getChunk()].push_back(s);
// Sort symbols by address.
for (auto &It : Ret) {
SmallVectorImpl<DefinedRegular *> &V = It.second;
std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
return A->getRVA() < B->getRVA();
for (auto &it : ret) {
SmallVectorImpl<DefinedRegular *> &v = it.second;
std::sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) {
return a->getRVA() < b->getRVA();
});
}
return Ret;
return ret;
}
// Construct a map from symbols to their stringified representations.
static DenseMap<DefinedRegular *, std::string>
getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
std::vector<std::string> Str(Syms.size());
parallelForEachN((size_t)0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
writeHeader(OS, Syms[I]->getRVA(), 0, 0);
OS << Indent16 << toString(*Syms[I]);
getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
std::vector<std::string> str(syms.size());
parallelForEachN((size_t)0, syms.size(), [&](size_t i) {
raw_string_ostream os(str[i]);
writeHeader(os, syms[i]->getRVA(), 0, 0);
os << indent16 << toString(*syms[i]);
});
DenseMap<DefinedRegular *, std::string> Ret;
for (size_t I = 0, E = Syms.size(); I < E; ++I)
Ret[Syms[I]] = std::move(Str[I]);
return Ret;
DenseMap<DefinedRegular *, std::string> ret;
for (size_t i = 0, e = syms.size(); i < e; ++i)
ret[syms[i]] = std::move(str[i]);
return ret;
}
void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
if (Config->MapFile.empty())
void coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
if (config->mapFile.empty())
return;
std::error_code EC;
raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
if (EC)
fatal("cannot open " + Config->MapFile + ": " + EC.message());
std::error_code ec;
raw_fd_ostream os(config->mapFile, ec, sys::fs::F_None);
if (ec)
fatal("cannot open " + config->mapFile + ": " + ec.message());
// Collect symbol info that we want to print out.
std::vector<DefinedRegular *> Syms = getSymbols();
SymbolMapTy SectionSyms = getSectionSyms(Syms);
DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms);
std::vector<DefinedRegular *> syms = getSymbols();
SymbolMapTy sectionSyms = getSectionSyms(syms);
DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
// Print out the header line.
OS << "Address Size Align Out In Symbol\n";
os << "Address Size Align Out In Symbol\n";
// Print out file contents.
for (OutputSection *Sec : OutputSections) {
writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
OS << Sec->Name << '\n';
for (OutputSection *sec : outputSections) {
writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*Align=*/pageSize);
os << sec->name << '\n';
for (Chunk *C : Sec->Chunks) {
auto *SC = dyn_cast<SectionChunk>(C);
if (!SC)
for (Chunk *c : sec->chunks) {
auto *sc = dyn_cast<SectionChunk>(c);
if (!sc)
continue;
writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlignment());
OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName()
writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment());
os << indent8 << sc->file->getName() << ":(" << sc->getSectionName()
<< ")\n";
for (DefinedRegular *Sym : SectionSyms[SC])
OS << SymStr[Sym] << '\n';
for (DefinedRegular *sym : sectionSyms[sc])
os << symStr[sym] << '\n';
}
}
}

View File

@ -14,7 +14,7 @@
namespace lld {
namespace coff {
class OutputSection;
void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
void writeMapFile(llvm::ArrayRef<OutputSection *> outputSections);
}
}

View File

@ -15,57 +15,57 @@
namespace lld {
namespace coff {
static Timer GCTimer("GC", Timer::root());
static Timer gCTimer("GC", Timer::root());
// Set live bit on for each reachable chunk. Unmarked (unreachable)
// COMDAT chunks will be ignored by Writer, so they will be excluded
// from the final output.
void markLive(ArrayRef<Chunk *> Chunks) {
ScopedTimer T(GCTimer);
void markLive(ArrayRef<Chunk *> chunks) {
ScopedTimer t(gCTimer);
// We build up a worklist of sections which have been marked as live. We only
// push into the worklist when we discover an unmarked section, and we mark
// as we push, so sections never appear twice in the list.
SmallVector<SectionChunk *, 256> Worklist;
SmallVector<SectionChunk *, 256> worklist;
// COMDAT section chunks are dead by default. Add non-COMDAT chunks.
for (Chunk *C : Chunks)
if (auto *SC = dyn_cast<SectionChunk>(C))
if (SC->Live)
Worklist.push_back(SC);
for (Chunk *c : chunks)
if (auto *sc = dyn_cast<SectionChunk>(c))
if (sc->live)
worklist.push_back(sc);
auto Enqueue = [&](SectionChunk *C) {
if (C->Live)
auto enqueue = [&](SectionChunk *c) {
if (c->live)
return;
C->Live = true;
Worklist.push_back(C);
c->live = true;
worklist.push_back(c);
};
auto AddSym = [&](Symbol *B) {
if (auto *Sym = dyn_cast<DefinedRegular>(B))
Enqueue(Sym->getChunk());
else if (auto *Sym = dyn_cast<DefinedImportData>(B))
Sym->File->Live = true;
else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true;
auto addSym = [&](Symbol *b) {
if (auto *sym = dyn_cast<DefinedRegular>(b))
enqueue(sym->getChunk());
else if (auto *sym = dyn_cast<DefinedImportData>(b))
sym->file->live = true;
else if (auto *sym = dyn_cast<DefinedImportThunk>(b))
sym->wrappedSym->file->live = sym->wrappedSym->file->thunkLive = true;
};
// Add GC root chunks.
for (Symbol *B : Config->GCRoot)
AddSym(B);
for (Symbol *b : config->gCRoot)
addSym(b);
while (!Worklist.empty()) {
SectionChunk *SC = Worklist.pop_back_val();
assert(SC->Live && "We mark as live when pushing onto the worklist!");
while (!worklist.empty()) {
SectionChunk *sc = worklist.pop_back_val();
assert(sc->live && "We mark as live when pushing onto the worklist!");
// Mark all symbols listed in the relocation table for this section.
for (Symbol *B : SC->symbols())
if (B)
AddSym(B);
for (Symbol *b : sc->symbols())
if (b)
addSym(b);
// Mark associative sections if any.
for (SectionChunk &C : SC->children())
Enqueue(&C);
for (SectionChunk &c : sc->children())
enqueue(&c);
}
}

View File

@ -17,7 +17,7 @@ namespace coff {
class Chunk;
void markLive(ArrayRef<Chunk *> Chunks);
void markLive(ArrayRef<Chunk *> chunks);
} // namespace coff
} // namespace lld

View File

@ -19,7 +19,7 @@ using namespace llvm;
using namespace llvm::COFF;
AutoExporter::AutoExporter() {
ExcludeLibs = {
excludeLibs = {
"libgcc",
"libgcc_s",
"libstdc++",
@ -41,12 +41,12 @@ AutoExporter::AutoExporter() {
"libucrtbase",
};
ExcludeObjects = {
excludeObjects = {
"crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o",
"dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o",
};
ExcludeSymbolPrefixes = {
excludeSymbolPrefixes = {
// Import symbols
"__imp_",
"__IMPORT_DESCRIPTOR_",
@ -59,13 +59,13 @@ AutoExporter::AutoExporter() {
".",
};
ExcludeSymbolSuffixes = {
excludeSymbolSuffixes = {
"_iname",
"_NULL_THUNK_DATA",
};
if (Config->Machine == I386) {
ExcludeSymbols = {
if (config->machine == I386) {
excludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
"__pei386_runtime_relocator",
"_do_pseudo_reloc",
@ -80,9 +80,9 @@ AutoExporter::AutoExporter() {
"_DllEntryPoint@12",
"_DllMainCRTStartup@12",
};
ExcludeSymbolPrefixes.insert("__head_");
excludeSymbolPrefixes.insert("__head_");
} else {
ExcludeSymbols = {
excludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
"_pei386_runtime_relocator",
"do_pseudo_reloc",
@ -97,70 +97,70 @@ AutoExporter::AutoExporter() {
"DllEntryPoint",
"DllMainCRTStartup",
};
ExcludeSymbolPrefixes.insert("_head_");
excludeSymbolPrefixes.insert("_head_");
}
}
void AutoExporter::addWholeArchive(StringRef Path) {
StringRef LibName = sys::path::filename(Path);
void AutoExporter::addWholeArchive(StringRef path) {
StringRef libName = sys::path::filename(path);
// Drop the file extension, to match the processing below.
LibName = LibName.substr(0, LibName.rfind('.'));
ExcludeLibs.erase(LibName);
libName = libName.substr(0, libName.rfind('.'));
excludeLibs.erase(libName);
}
bool AutoExporter::shouldExport(Defined *Sym) const {
if (!Sym || !Sym->isLive() || !Sym->getChunk())
bool AutoExporter::shouldExport(Defined *sym) const {
if (!sym || !sym->isLive() || !sym->getChunk())
return false;
// Only allow the symbol kinds that make sense to export; in particular,
// disallow import symbols.
if (!isa<DefinedRegular>(Sym) && !isa<DefinedCommon>(Sym))
if (!isa<DefinedRegular>(sym) && !isa<DefinedCommon>(sym))
return false;
if (ExcludeSymbols.count(Sym->getName()))
if (excludeSymbols.count(sym->getName()))
return false;
for (StringRef Prefix : ExcludeSymbolPrefixes.keys())
if (Sym->getName().startswith(Prefix))
for (StringRef prefix : excludeSymbolPrefixes.keys())
if (sym->getName().startswith(prefix))
return false;
for (StringRef Suffix : ExcludeSymbolSuffixes.keys())
if (Sym->getName().endswith(Suffix))
for (StringRef suffix : excludeSymbolSuffixes.keys())
if (sym->getName().endswith(suffix))
return false;
// If a corresponding __imp_ symbol exists and is defined, don't export it.
if (Symtab->find(("__imp_" + Sym->getName()).str()))
if (symtab->find(("__imp_" + sym->getName()).str()))
return false;
// Check that file is non-null before dereferencing it, symbols not
// originating in regular object files probably shouldn't be exported.
if (!Sym->getFile())
if (!sym->getFile())
return false;
StringRef LibName = sys::path::filename(Sym->getFile()->ParentName);
StringRef libName = sys::path::filename(sym->getFile()->parentName);
// Drop the file extension.
LibName = LibName.substr(0, LibName.rfind('.'));
if (!LibName.empty())
return !ExcludeLibs.count(LibName);
libName = libName.substr(0, libName.rfind('.'));
if (!libName.empty())
return !excludeLibs.count(libName);
StringRef FileName = sys::path::filename(Sym->getFile()->getName());
return !ExcludeObjects.count(FileName);
StringRef fileName = sys::path::filename(sym->getFile()->getName());
return !excludeObjects.count(fileName);
}
void coff::writeDefFile(StringRef Name) {
std::error_code EC;
raw_fd_ostream OS(Name, EC, sys::fs::F_None);
if (EC)
fatal("cannot open " + Name + ": " + EC.message());
void coff::writeDefFile(StringRef name) {
std::error_code ec;
raw_fd_ostream os(name, ec, sys::fs::F_None);
if (ec)
fatal("cannot open " + name + ": " + ec.message());
OS << "EXPORTS\n";
for (Export &E : Config->Exports) {
OS << " " << E.ExportName << " "
<< "@" << E.Ordinal;
if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) {
if (Def && Def->getChunk() &&
!(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
OS << " DATA";
os << "EXPORTS\n";
for (Export &e : config->exports) {
os << " " << e.exportName << " "
<< "@" << e.ordinal;
if (auto *def = dyn_cast_or_null<Defined>(e.sym)) {
if (def && def->getChunk() &&
!(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
os << " DATA";
}
OS << "\n";
os << "\n";
}
}

View File

@ -22,18 +22,18 @@ class AutoExporter {
public:
AutoExporter();
void addWholeArchive(StringRef Path);
void addWholeArchive(StringRef path);
llvm::StringSet<> ExcludeSymbols;
llvm::StringSet<> ExcludeSymbolPrefixes;
llvm::StringSet<> ExcludeSymbolSuffixes;
llvm::StringSet<> ExcludeLibs;
llvm::StringSet<> ExcludeObjects;
llvm::StringSet<> excludeSymbols;
llvm::StringSet<> excludeSymbolPrefixes;
llvm::StringSet<> excludeSymbolSuffixes;
llvm::StringSet<> excludeLibs;
llvm::StringSet<> excludeObjects;
bool shouldExport(Defined *Sym) const;
bool shouldExport(Defined *sym) const;
};
void writeDefFile(StringRef Name);
void writeDefFile(StringRef name);
} // namespace coff
} // namespace lld

File diff suppressed because it is too large Load Diff

View File

@ -24,13 +24,13 @@ class OutputSection;
class SectionChunk;
class SymbolTable;
void createPDB(SymbolTable *Symtab,
llvm::ArrayRef<OutputSection *> OutputSections,
llvm::ArrayRef<uint8_t> SectionTable,
llvm::codeview::DebugInfo *BuildId);
void createPDB(SymbolTable *symtab,
llvm::ArrayRef<OutputSection *> outputSections,
llvm::ArrayRef<uint8_t> sectionTable,
llvm::codeview::DebugInfo *buildId);
std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
uint32_t Addr);
std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *c,
uint32_t addr);
}
}

View File

@ -26,168 +26,168 @@ using namespace llvm;
namespace lld {
namespace coff {
static Timer LTOTimer("LTO", Timer::root());
static Timer ltoTimer("LTO", Timer::root());
SymbolTable *Symtab;
SymbolTable *symtab;
void SymbolTable::addFile(InputFile *File) {
log("Reading " + toString(File));
File->parse();
void SymbolTable::addFile(InputFile *file) {
log("Reading " + toString(file));
file->parse();
MachineTypes MT = File->getMachineType();
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
Config->Machine = MT;
} else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
error(toString(File) + ": machine type " + machineToStr(MT) +
" conflicts with " + machineToStr(Config->Machine));
MachineTypes mt = file->getMachineType();
if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
config->machine = mt;
} else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && config->machine != mt) {
error(toString(file) + ": machine type " + machineToStr(mt) +
" conflicts with " + machineToStr(config->machine));
return;
}
if (auto *F = dyn_cast<ObjFile>(File)) {
ObjFile::Instances.push_back(F);
} else if (auto *F = dyn_cast<BitcodeFile>(File)) {
BitcodeFile::Instances.push_back(F);
} else if (auto *F = dyn_cast<ImportFile>(File)) {
ImportFile::Instances.push_back(F);
if (auto *f = dyn_cast<ObjFile>(file)) {
ObjFile::instances.push_back(f);
} else if (auto *f = dyn_cast<BitcodeFile>(file)) {
BitcodeFile::instances.push_back(f);
} else if (auto *f = dyn_cast<ImportFile>(file)) {
ImportFile::instances.push_back(f);
}
Driver->parseDirectives(File);
driver->parseDirectives(file);
}
static void errorOrWarn(const Twine &S) {
if (Config->ForceUnresolved)
warn(S);
static void errorOrWarn(const Twine &s) {
if (config->forceUnresolved)
warn(s);
else
error(S);
error(s);
}
// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
// This is generally the global variable or function whose definition contains
// Addr.
static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) {
DefinedRegular *Candidate = nullptr;
static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
DefinedRegular *candidate = nullptr;
for (Symbol *S : SC->File->getSymbols()) {
auto *D = dyn_cast_or_null<DefinedRegular>(S);
if (!D || D->getChunk() != SC || D->getValue() > Addr ||
(Candidate && D->getValue() < Candidate->getValue()))
for (Symbol *s : sc->file->getSymbols()) {
auto *d = dyn_cast_or_null<DefinedRegular>(s);
if (!d || d->getChunk() != sc || d->getValue() > addr ||
(candidate && d->getValue() < candidate->getValue()))
continue;
Candidate = D;
candidate = d;
}
return Candidate;
return candidate;
}
// Given a file and the index of a symbol in that file, returns a description
// of all references to that symbol from that file. If no debug information is
// available, returns just the name of the file, else one string per actual
// reference as described in the debug info.
std::vector<std::string> getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
struct Location {
Symbol *Sym;
std::pair<StringRef, uint32_t> FileLine;
Symbol *sym;
std::pair<StringRef, uint32_t> fileLine;
};
std::vector<Location> Locations;
std::vector<Location> locations;
for (Chunk *C : File->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
if (!SC)
for (Chunk *c : file->getChunks()) {
auto *sc = dyn_cast<SectionChunk>(c);
if (!sc)
continue;
for (const coff_relocation &R : SC->getRelocs()) {
if (R.SymbolTableIndex != SymIndex)
for (const coff_relocation &r : sc->getRelocs()) {
if (r.SymbolTableIndex != symIndex)
continue;
std::pair<StringRef, uint32_t> FileLine =
getFileLine(SC, R.VirtualAddress);
Symbol *Sym = getSymbol(SC, R.VirtualAddress);
if (!FileLine.first.empty() || Sym)
Locations.push_back({Sym, FileLine});
std::pair<StringRef, uint32_t> fileLine =
getFileLine(sc, r.VirtualAddress);
Symbol *sym = getSymbol(sc, r.VirtualAddress);
if (!fileLine.first.empty() || sym)
locations.push_back({sym, fileLine});
}
}
if (Locations.empty())
return std::vector<std::string>({"\n>>> referenced by " + toString(File)});
if (locations.empty())
return std::vector<std::string>({"\n>>> referenced by " + toString(file)});
std::vector<std::string> SymbolLocations(Locations.size());
size_t I = 0;
for (Location Loc : Locations) {
llvm::raw_string_ostream OS(SymbolLocations[I++]);
OS << "\n>>> referenced by ";
if (!Loc.FileLine.first.empty())
OS << Loc.FileLine.first << ":" << Loc.FileLine.second
std::vector<std::string> symbolLocations(locations.size());
size_t i = 0;
for (Location loc : locations) {
llvm::raw_string_ostream os(symbolLocations[i++]);
os << "\n>>> referenced by ";
if (!loc.fileLine.first.empty())
os << loc.fileLine.first << ":" << loc.fileLine.second
<< "\n>>> ";
OS << toString(File);
if (Loc.Sym)
OS << ":(" << toString(*Loc.Sym) << ')';
os << toString(file);
if (loc.sym)
os << ":(" << toString(*loc.sym) << ')';
}
return SymbolLocations;
return symbolLocations;
}
// For an undefined symbol, stores all files referencing it and the index of
// the undefined symbol in each file.
struct UndefinedDiag {
Symbol *Sym;
Symbol *sym;
struct File {
ObjFile *OFile;
uint64_t SymIndex;
ObjFile *oFile;
uint64_t symIndex;
};
std::vector<File> Files;
std::vector<File> files;
};
static void reportUndefinedSymbol(const UndefinedDiag &UndefDiag) {
std::string Out;
llvm::raw_string_ostream OS(Out);
OS << "undefined symbol: " << toString(*UndefDiag.Sym);
static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
std::string out;
llvm::raw_string_ostream os(out);
os << "undefined symbol: " << toString(*undefDiag.sym);
const size_t MaxUndefReferences = 10;
size_t I = 0, NumRefs = 0;
for (const UndefinedDiag::File &Ref : UndefDiag.Files) {
std::vector<std::string> SymbolLocations =
getSymbolLocations(Ref.OFile, Ref.SymIndex);
NumRefs += SymbolLocations.size();
for (const std::string &S : SymbolLocations) {
if (I >= MaxUndefReferences)
const size_t maxUndefReferences = 10;
size_t i = 0, numRefs = 0;
for (const UndefinedDiag::File &ref : undefDiag.files) {
std::vector<std::string> symbolLocations =
getSymbolLocations(ref.oFile, ref.symIndex);
numRefs += symbolLocations.size();
for (const std::string &s : symbolLocations) {
if (i >= maxUndefReferences)
break;
OS << S;
I++;
os << s;
i++;
}
}
if (I < NumRefs)
OS << "\n>>> referenced " << NumRefs - I << " more times";
errorOrWarn(OS.str());
if (i < numRefs)
os << "\n>>> referenced " << numRefs - i << " more times";
errorOrWarn(os.str());
}
void SymbolTable::loadMinGWAutomaticImports() {
for (auto &I : SymMap) {
Symbol *Sym = I.second;
auto *Undef = dyn_cast<Undefined>(Sym);
if (!Undef)
for (auto &i : symMap) {
Symbol *sym = i.second;
auto *undef = dyn_cast<Undefined>(sym);
if (!undef)
continue;
if (!Sym->IsUsedInRegularObj)
if (!sym->isUsedInRegularObj)
continue;
StringRef Name = Undef->getName();
StringRef name = undef->getName();
if (Name.startswith("__imp_"))
if (name.startswith("__imp_"))
continue;
// If we have an undefined symbol, but we have a Lazy representing a
// symbol we could load from file, make sure to load that.
Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str()));
if (!L || L->PendingArchiveLoad)
Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str()));
if (!l || l->pendingArchiveLoad)
continue;
log("Loading lazy " + L->getName() + " from " + L->File->getName() +
log("Loading lazy " + l->getName() + " from " + l->file->getName() +
" for automatic import");
L->PendingArchiveLoad = true;
L->File->addMember(&L->Sym);
l->pendingArchiveLoad = true;
l->file->addMember(&l->sym);
}
}
bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
if (Name.startswith("__imp_"))
bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
if (name.startswith("__imp_"))
return false;
Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str()));
if (!Imp)
Defined *imp = dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
if (!imp)
return false;
// Replace the reference directly to a variable with a reference
@ -196,406 +196,406 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
// will add runtime pseudo relocations for every relocation against
// this Symbol. The runtime pseudo relocation framework expects the
// reference itself to point at the IAT entry.
size_t ImpSize = 0;
if (isa<DefinedImportData>(Imp)) {
log("Automatically importing " + Name + " from " +
cast<DefinedImportData>(Imp)->getDLLName());
ImpSize = sizeof(DefinedImportData);
} else if (isa<DefinedRegular>(Imp)) {
log("Automatically importing " + Name + " from " +
toString(cast<DefinedRegular>(Imp)->File));
ImpSize = sizeof(DefinedRegular);
size_t impSize = 0;
if (isa<DefinedImportData>(imp)) {
log("Automatically importing " + name + " from " +
cast<DefinedImportData>(imp)->getDLLName());
impSize = sizeof(DefinedImportData);
} else if (isa<DefinedRegular>(imp)) {
log("Automatically importing " + name + " from " +
toString(cast<DefinedRegular>(imp)->file));
impSize = sizeof(DefinedRegular);
} else {
warn("unable to automatically import " + Name + " from " + Imp->getName() +
" from " + toString(cast<DefinedRegular>(Imp)->File) +
warn("unable to automatically import " + name + " from " + imp->getName() +
" from " + toString(cast<DefinedRegular>(imp)->file) +
"; unexpected symbol type");
return false;
}
Sym->replaceKeepingName(Imp, ImpSize);
Sym->IsRuntimePseudoReloc = true;
sym->replaceKeepingName(imp, impSize);
sym->isRuntimePseudoReloc = true;
// There may exist symbols named .refptr.<name> which only consist
// of a single pointer to <name>. If it turns out <name> is
// automatically imported, we don't need to keep the .refptr.<name>
// pointer at all, but redirect all accesses to it to the IAT entry
// for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
DefinedRegular *Refptr =
dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
if (SC && SC->getRelocs().size() == 1 && *SC->symbols().begin() == Sym) {
log("Replacing .refptr." + Name + " with " + Imp->getName());
Refptr->getChunk()->Live = false;
Refptr->replaceKeepingName(Imp, ImpSize);
DefinedRegular *refptr =
dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));
if (refptr && refptr->getChunk()->getSize() == config->wordsize) {
SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());
if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
log("Replacing .refptr." + name + " with " + imp->getName());
refptr->getChunk()->live = false;
refptr->replaceKeepingName(imp, impSize);
}
}
return true;
}
void SymbolTable::reportRemainingUndefines() {
SmallPtrSet<Symbol *, 8> Undefs;
DenseMap<Symbol *, Symbol *> LocalImports;
SmallPtrSet<Symbol *, 8> undefs;
DenseMap<Symbol *, Symbol *> localImports;
for (auto &I : SymMap) {
Symbol *Sym = I.second;
auto *Undef = dyn_cast<Undefined>(Sym);
if (!Undef)
for (auto &i : symMap) {
Symbol *sym = i.second;
auto *undef = dyn_cast<Undefined>(sym);
if (!undef)
continue;
if (!Sym->IsUsedInRegularObj)
if (!sym->isUsedInRegularObj)
continue;
StringRef Name = Undef->getName();
StringRef name = undef->getName();
// A weak alias may have been resolved, so check for that.
if (Defined *D = Undef->getWeakAlias()) {
if (Defined *d = undef->getWeakAlias()) {
// We want to replace Sym with D. However, we can't just blindly
// copy sizeof(SymbolUnion) bytes from D to Sym because D may be an
// internal symbol, and internal symbols are stored as "unparented"
// Symbols. For that reason we need to check which type of symbol we
// are dealing with and copy the correct number of bytes.
if (isa<DefinedRegular>(D))
memcpy(Sym, D, sizeof(DefinedRegular));
else if (isa<DefinedAbsolute>(D))
memcpy(Sym, D, sizeof(DefinedAbsolute));
if (isa<DefinedRegular>(d))
memcpy(sym, d, sizeof(DefinedRegular));
else if (isa<DefinedAbsolute>(d))
memcpy(sym, d, sizeof(DefinedAbsolute));
else
memcpy(Sym, D, sizeof(SymbolUnion));
memcpy(sym, d, sizeof(SymbolUnion));
continue;
}
// If we can resolve a symbol by removing __imp_ prefix, do that.
// This odd rule is for compatibility with MSVC linker.
if (Name.startswith("__imp_")) {
Symbol *Imp = find(Name.substr(strlen("__imp_")));
if (Imp && isa<Defined>(Imp)) {
auto *D = cast<Defined>(Imp);
replaceSymbol<DefinedLocalImport>(Sym, Name, D);
LocalImportChunks.push_back(cast<DefinedLocalImport>(Sym)->getChunk());
LocalImports[Sym] = D;
if (name.startswith("__imp_")) {
Symbol *imp = find(name.substr(strlen("__imp_")));
if (imp && isa<Defined>(imp)) {
auto *d = cast<Defined>(imp);
replaceSymbol<DefinedLocalImport>(sym, name, d);
localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());
localImports[sym] = d;
continue;
}
}
// We don't want to report missing Microsoft precompiled headers symbols.
// A proper message will be emitted instead in PDBLinker::aquirePrecompObj
if (Name.contains("_PchSym_"))
if (name.contains("_PchSym_"))
continue;
if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name))
if (config->mingw && handleMinGWAutomaticImport(sym, name))
continue;
// Remaining undefined symbols are not fatal if /force is specified.
// They are replaced with dummy defined symbols.
if (Config->ForceUnresolved)
replaceSymbol<DefinedAbsolute>(Sym, Name, 0);
Undefs.insert(Sym);
if (config->forceUnresolved)
replaceSymbol<DefinedAbsolute>(sym, name, 0);
undefs.insert(sym);
}
if (Undefs.empty() && LocalImports.empty())
if (undefs.empty() && localImports.empty())
return;
for (Symbol *B : Config->GCRoot) {
if (Undefs.count(B))
errorOrWarn("<root>: undefined symbol: " + toString(*B));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(B))
warn("<root>: locally defined symbol imported: " + toString(*Imp) +
" (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
for (Symbol *b : config->gCRoot) {
if (undefs.count(b))
errorOrWarn("<root>: undefined symbol: " + toString(*b));
if (config->warnLocallyDefinedImported)
if (Symbol *imp = localImports.lookup(b))
warn("<root>: locally defined symbol imported: " + toString(*imp) +
" (defined in " + toString(imp->getFile()) + ") [LNK4217]");
}
std::vector<UndefinedDiag> UndefDiags;
DenseMap<Symbol *, int> FirstDiag;
std::vector<UndefinedDiag> undefDiags;
DenseMap<Symbol *, int> firstDiag;
for (ObjFile *File : ObjFile::Instances) {
size_t SymIndex = (size_t)-1;
for (Symbol *Sym : File->getSymbols()) {
++SymIndex;
if (!Sym)
for (ObjFile *file : ObjFile::instances) {
size_t symIndex = (size_t)-1;
for (Symbol *sym : file->getSymbols()) {
++symIndex;
if (!sym)
continue;
if (Undefs.count(Sym)) {
auto it = FirstDiag.find(Sym);
if (it == FirstDiag.end()) {
FirstDiag[Sym] = UndefDiags.size();
UndefDiags.push_back({Sym, {{File, SymIndex}}});
if (undefs.count(sym)) {
auto it = firstDiag.find(sym);
if (it == firstDiag.end()) {
firstDiag[sym] = undefDiags.size();
undefDiags.push_back({sym, {{file, symIndex}}});
} else {
UndefDiags[it->second].Files.push_back({File, SymIndex});
undefDiags[it->second].files.push_back({file, symIndex});
}
}
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(Sym))
warn(toString(File) +
": locally defined symbol imported: " + toString(*Imp) +
" (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
if (config->warnLocallyDefinedImported)
if (Symbol *imp = localImports.lookup(sym))
warn(toString(file) +
": locally defined symbol imported: " + toString(*imp) +
" (defined in " + toString(imp->getFile()) + ") [LNK4217]");
}
}
for (const UndefinedDiag& UndefDiag : UndefDiags)
reportUndefinedSymbol(UndefDiag);
for (const UndefinedDiag& undefDiag : undefDiags)
reportUndefinedSymbol(undefDiag);
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
bool Inserted = false;
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
if (!Sym) {
Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
Sym->IsUsedInRegularObj = false;
Sym->PendingArchiveLoad = false;
Inserted = true;
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
bool inserted = false;
Symbol *&sym = symMap[CachedHashStringRef(name)];
if (!sym) {
sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
sym->isUsedInRegularObj = false;
sym->pendingArchiveLoad = false;
inserted = true;
}
return {Sym, Inserted};
return {sym, inserted};
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
std::pair<Symbol *, bool> Result = insert(Name);
if (!File || !isa<BitcodeFile>(File))
Result.first->IsUsedInRegularObj = true;
return Result;
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
std::pair<Symbol *, bool> result = insert(name);
if (!file || !isa<BitcodeFile>(file))
result.first->isUsedInRegularObj = true;
return result;
}
Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,
bool IsWeakAlias) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, F);
if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) {
replaceSymbol<Undefined>(S, Name);
return S;
Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
bool isWeakAlias) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name, f);
if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) {
replaceSymbol<Undefined>(s, name);
return s;
}
if (auto *L = dyn_cast<Lazy>(S)) {
if (!S->PendingArchiveLoad) {
S->PendingArchiveLoad = true;
L->File->addMember(&L->Sym);
if (auto *l = dyn_cast<Lazy>(s)) {
if (!s->pendingArchiveLoad) {
s->pendingArchiveLoad = true;
l->file->addMember(&l->sym);
}
}
return S;
return s;
}
void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
StringRef Name = Sym.getName();
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceSymbol<Lazy>(S, F, Sym);
void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol sym) {
StringRef name = sym.getName();
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name);
if (wasInserted) {
replaceSymbol<Lazy>(s, f, sym);
return;
}
auto *U = dyn_cast<Undefined>(S);
if (!U || U->WeakAlias || S->PendingArchiveLoad)
auto *u = dyn_cast<Undefined>(s);
if (!u || u->weakAlias || s->pendingArchiveLoad)
return;
S->PendingArchiveLoad = true;
F->addMember(&Sym);
s->pendingArchiveLoad = true;
f->addMember(&sym);
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " +
toString(Existing->getFile()) + " and in " +
toString(NewFile);
void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) {
std::string msg = "duplicate symbol: " + toString(*existing) + " in " +
toString(existing->getFile()) + " and in " +
toString(newFile);
if (Config->ForceMultiple)
warn(Msg);
if (config->forceMultiple)
warn(msg);
else
error(Msg);
error(msg);
}
Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedAbsolute>(S, N, Sym);
else if (!isa<DefinedCOFF>(S))
reportDuplicate(S, nullptr);
return S;
Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
replaceSymbol<DefinedAbsolute>(s, n, sym);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
return s;
}
Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedAbsolute>(S, N, VA);
else if (!isa<DefinedCOFF>(S))
reportDuplicate(S, nullptr);
return S;
Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
replaceSymbol<DefinedAbsolute>(s, n, va);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
return s;
}
Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedSynthetic>(S, N, C);
else if (!isa<DefinedCOFF>(S))
reportDuplicate(S, nullptr);
return S;
Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
replaceSymbol<DefinedSynthetic>(s, n, c);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
return s;
}
Symbol *SymbolTable::addRegular(InputFile *F, StringRef N,
const coff_symbol_generic *Sym,
SectionChunk *C) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedRegular>(S))
replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false,
/*IsExternal*/ true, Sym, C);
Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
const coff_symbol_generic *sym,
SectionChunk *c) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, f);
if (wasInserted || !isa<DefinedRegular>(s))
replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,
/*IsExternal*/ true, sym, c);
else
reportDuplicate(S, F);
return S;
reportDuplicate(s, f);
return s;
}
std::pair<DefinedRegular *, bool>
SymbolTable::addComdat(InputFile *F, StringRef N,
const coff_symbol_generic *Sym) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedRegular>(S)) {
replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true,
/*IsExternal*/ true, Sym, nullptr);
return {cast<DefinedRegular>(S), true};
SymbolTable::addComdat(InputFile *f, StringRef n,
const coff_symbol_generic *sym) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, f);
if (wasInserted || !isa<DefinedRegular>(s)) {
replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,
/*IsExternal*/ true, sym, nullptr);
return {cast<DefinedRegular>(s), true};
}
auto *ExistingSymbol = cast<DefinedRegular>(S);
if (!ExistingSymbol->IsCOMDAT)
reportDuplicate(S, F);
return {ExistingSymbol, false};
auto *existingSymbol = cast<DefinedRegular>(s);
if (!existingSymbol->isCOMDAT)
reportDuplicate(s, f);
return {existingSymbol, false};
}
Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
const coff_symbol_generic *Sym, CommonChunk *C) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedCOFF>(S))
replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S))
if (Size > DC->getSize())
replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
return S;
Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
const coff_symbol_generic *sym, CommonChunk *c) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, f);
if (wasInserted || !isa<DefinedCOFF>(s))
replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
else if (auto *dc = dyn_cast<DefinedCommon>(s))
if (size > dc->getSize())
replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
return s;
}
Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportData>(S, N, F);
return S;
Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
replaceSymbol<DefinedImportData>(s, n, f);
return s;
}
reportDuplicate(S, F);
reportDuplicate(s, f);
return nullptr;
}
Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
uint16_t Machine) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);
return S;
Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
uint16_t machine) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name, nullptr);
s->isUsedInRegularObj = true;
if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
replaceSymbol<DefinedImportThunk>(s, name, id, machine);
return s;
}
reportDuplicate(S, ID->File);
reportDuplicate(s, id->file);
return nullptr;
}
std::vector<Chunk *> SymbolTable::getChunks() {
std::vector<Chunk *> Res;
for (ObjFile *File : ObjFile::Instances) {
ArrayRef<Chunk *> V = File->getChunks();
Res.insert(Res.end(), V.begin(), V.end());
std::vector<Chunk *> res;
for (ObjFile *file : ObjFile::instances) {
ArrayRef<Chunk *> v = file->getChunks();
res.insert(res.end(), v.begin(), v.end());
}
return Res;
return res;
}
Symbol *SymbolTable::find(StringRef Name) {
return SymMap.lookup(CachedHashStringRef(Name));
Symbol *SymbolTable::find(StringRef name) {
return symMap.lookup(CachedHashStringRef(name));
}
Symbol *SymbolTable::findUnderscore(StringRef Name) {
if (Config->Machine == I386)
return find(("_" + Name).str());
return find(Name);
Symbol *SymbolTable::findUnderscore(StringRef name) {
if (config->machine == I386)
return find(("_" + name).str());
return find(name);
}
// Return all symbols that start with Prefix, possibly ignoring the first
// character of Prefix or the first character symbol.
std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef Prefix) {
std::vector<Symbol *> Syms;
for (auto Pair : SymMap) {
StringRef Name = Pair.first.val();
if (Name.startswith(Prefix) || Name.startswith(Prefix.drop_front()) ||
Name.drop_front().startswith(Prefix) ||
Name.drop_front().startswith(Prefix.drop_front())) {
Syms.push_back(Pair.second);
std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
std::vector<Symbol *> syms;
for (auto pair : symMap) {
StringRef name = pair.first.val();
if (name.startswith(prefix) || name.startswith(prefix.drop_front()) ||
name.drop_front().startswith(prefix) ||
name.drop_front().startswith(prefix.drop_front())) {
syms.push_back(pair.second);
}
}
return Syms;
return syms;
}
Symbol *SymbolTable::findMangle(StringRef Name) {
if (Symbol *Sym = find(Name))
if (!isa<Undefined>(Sym))
return Sym;
Symbol *SymbolTable::findMangle(StringRef name) {
if (Symbol *sym = find(name))
if (!isa<Undefined>(sym))
return sym;
// Efficient fuzzy string lookup is impossible with a hash table, so iterate
// the symbol table once and collect all possibly matching symbols into this
// vector. Then compare each possibly matching symbol with each possible
// mangling.
std::vector<Symbol *> Syms = getSymsWithPrefix(Name);
auto FindByPrefix = [&Syms](const Twine &T) -> Symbol * {
std::string Prefix = T.str();
for (auto *S : Syms)
if (S->getName().startswith(Prefix))
return S;
std::vector<Symbol *> syms = getSymsWithPrefix(name);
auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
std::string prefix = t.str();
for (auto *s : syms)
if (s->getName().startswith(prefix))
return s;
return nullptr;
};
// For non-x86, just look for C++ functions.
if (Config->Machine != I386)
return FindByPrefix("?" + Name + "@@Y");
if (config->machine != I386)
return findByPrefix("?" + name + "@@Y");
if (!Name.startswith("_"))
if (!name.startswith("_"))
return nullptr;
// Search for x86 stdcall function.
if (Symbol *S = FindByPrefix(Name + "@"))
return S;
if (Symbol *s = findByPrefix(name + "@"))
return s;
// Search for x86 fastcall function.
if (Symbol *S = FindByPrefix("@" + Name.substr(1) + "@"))
return S;
if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))
return s;
// Search for x86 vectorcall function.
if (Symbol *S = FindByPrefix(Name.substr(1) + "@@"))
return S;
if (Symbol *s = findByPrefix(name.substr(1) + "@@"))
return s;
// Search for x86 C++ non-member function.
return FindByPrefix("?" + Name.substr(1) + "@@Y");
return findByPrefix("?" + name.substr(1) + "@@Y");
}
Symbol *SymbolTable::addUndefined(StringRef Name) {
return addUndefined(Name, nullptr, false);
Symbol *SymbolTable::addUndefined(StringRef name) {
return addUndefined(name, nullptr, false);
}
std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFile::Instances)
LTO->add(*F);
return LTO->compile();
lto.reset(new BitcodeCompiler);
for (BitcodeFile *f : BitcodeFile::instances)
lto->add(*f);
return lto->compile();
}
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFile::Instances.empty())
if (BitcodeFile::instances.empty())
return;
ScopedTimer T(LTOTimer);
for (StringRef Object : compileBitcodeFiles()) {
auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
ObjFile::Instances.push_back(Obj);
ScopedTimer t(ltoTimer);
for (StringRef object : compileBitcodeFiles()) {
auto *obj = make<ObjFile>(MemoryBufferRef(object, "lto.tmp"));
obj->parse();
ObjFile::instances.push_back(obj);
}
}

View File

@ -47,7 +47,7 @@ class Symbol;
// There is one add* function per symbol type.
class SymbolTable {
public:
void addFile(InputFile *File);
void addFile(InputFile *file);
// Try to resolve any undefined symbols and update the symbol table
// accordingly, then print an error message for any remaining undefined
@ -55,20 +55,20 @@ public:
void reportRemainingUndefines();
void loadMinGWAutomaticImports();
bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name);
bool handleMinGWAutomaticImport(Symbol *sym, StringRef name);
// Returns a list of chunks of selected symbols.
std::vector<Chunk *> getChunks();
// Returns a symbol for a given name. Returns a nullptr if not found.
Symbol *find(StringRef Name);
Symbol *findUnderscore(StringRef Name);
Symbol *find(StringRef name);
Symbol *findUnderscore(StringRef name);
// Occasionally we have to resolve an undefined symbol to its
// mangled symbol. This function tries to find a mangled name
// for U from the symbol table, and if found, set the symbol as
// a weak alias for U.
Symbol *findMangle(StringRef Name);
Symbol *findMangle(StringRef name);
// Build a set of COFF objects representing the combined contents of
// BitcodeFiles and add them to the symbol table. Called after all files are
@ -77,53 +77,53 @@ public:
std::vector<StringRef> compileBitcodeFiles();
// Creates an Undefined symbol for a given name.
Symbol *addUndefined(StringRef Name);
Symbol *addUndefined(StringRef name);
Symbol *addSynthetic(StringRef N, Chunk *C);
Symbol *addAbsolute(StringRef N, uint64_t VA);
Symbol *addSynthetic(StringRef n, Chunk *c);
Symbol *addAbsolute(StringRef n, uint64_t va);
Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
Symbol *addRegular(InputFile *F, StringRef N,
const llvm::object::coff_symbol_generic *S = nullptr,
SectionChunk *C = nullptr);
Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias);
void addLazy(ArchiveFile *f, const Archive::Symbol sym);
Symbol *addAbsolute(StringRef n, COFFSymbolRef s);
Symbol *addRegular(InputFile *f, StringRef n,
const llvm::object::coff_symbol_generic *s = nullptr,
SectionChunk *c = nullptr);
std::pair<DefinedRegular *, bool>
addComdat(InputFile *F, StringRef N,
const llvm::object::coff_symbol_generic *S = nullptr);
Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
const llvm::object::coff_symbol_generic *S = nullptr,
CommonChunk *C = nullptr);
Symbol *addImportData(StringRef N, ImportFile *F);
Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
uint16_t Machine);
addComdat(InputFile *f, StringRef n,
const llvm::object::coff_symbol_generic *s = nullptr);
Symbol *addCommon(InputFile *f, StringRef n, uint64_t size,
const llvm::object::coff_symbol_generic *s = nullptr,
CommonChunk *c = nullptr);
Symbol *addImportData(StringRef n, ImportFile *f);
Symbol *addImportThunk(StringRef name, DefinedImportData *s,
uint16_t machine);
void reportDuplicate(Symbol *Existing, InputFile *NewFile);
void reportDuplicate(Symbol *existing, InputFile *newFile);
// A list of chunks which to be added to .rdata.
std::vector<Chunk *> LocalImportChunks;
std::vector<Chunk *> localImportChunks;
// Iterates symbols in non-determinstic hash table order.
template <typename T> void forEachSymbol(T Callback) {
for (auto &Pair : SymMap)
Callback(Pair.second);
template <typename T> void forEachSymbol(T callback) {
for (auto &pair : symMap)
callback(pair.second);
}
private:
/// Inserts symbol if not already present.
std::pair<Symbol *, bool> insert(StringRef Name);
std::pair<Symbol *, bool> insert(StringRef name);
/// Same as insert(Name), but also sets IsUsedInRegularObj.
std::pair<Symbol *, bool> insert(StringRef Name, InputFile *F);
std::pair<Symbol *, bool> insert(StringRef name, InputFile *f);
std::vector<Symbol *> getSymsWithPrefix(StringRef Prefix);
std::vector<Symbol *> getSymsWithPrefix(StringRef prefix);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
std::unique_ptr<BitcodeCompiler> LTO;
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> symMap;
std::unique_ptr<BitcodeCompiler> lto;
};
extern SymbolTable *Symtab;
extern SymbolTable *symtab;
std::vector<std::string> getSymbolLocations(ObjFile *File, uint32_t SymIndex);
std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex);
} // namespace coff
} // namespace lld

View File

@ -24,11 +24,11 @@ static_assert(sizeof(SymbolUnion) <= 48,
"symbols should be optimized for memory usage");
// Returns a symbol name for an error message.
std::string lld::toString(coff::Symbol &B) {
if (Config->Demangle)
if (Optional<std::string> S = lld::demangleMSVC(B.getName()))
return *S;
return B.getName();
std::string lld::toString(coff::Symbol &b) {
if (config->demangle)
if (Optional<std::string> s = lld::demangleMSVC(b.getName()))
return *s;
return b.getName();
}
namespace lld {
@ -42,75 +42,75 @@ StringRef Symbol::getName() {
// name. Object files contain lots of non-external symbols, and creating
// StringRefs for them (which involves lots of strlen() on the string table)
// is a waste of time.
if (NameData == nullptr) {
auto *D = cast<DefinedCOFF>(this);
StringRef NameStr;
cast<ObjFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, NameStr);
NameData = NameStr.data();
NameSize = NameStr.size();
assert(NameSize == NameStr.size() && "name length truncated");
if (nameData == nullptr) {
auto *d = cast<DefinedCOFF>(this);
StringRef nameStr;
cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym, nameStr);
nameData = nameStr.data();
nameSize = nameStr.size();
assert(nameSize == nameStr.size() && "name length truncated");
}
return StringRef(NameData, NameSize);
return StringRef(nameData, nameSize);
}
InputFile *Symbol::getFile() {
if (auto *Sym = dyn_cast<DefinedCOFF>(this))
return Sym->File;
if (auto *Sym = dyn_cast<Lazy>(this))
return Sym->File;
if (auto *sym = dyn_cast<DefinedCOFF>(this))
return sym->file;
if (auto *sym = dyn_cast<Lazy>(this))
return sym->file;
return nullptr;
}
bool Symbol::isLive() const {
if (auto *R = dyn_cast<DefinedRegular>(this))
return R->getChunk()->Live;
if (auto *Imp = dyn_cast<DefinedImportData>(this))
return Imp->File->Live;
if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
return Imp->WrappedSym->File->ThunkLive;
if (auto *r = dyn_cast<DefinedRegular>(this))
return r->getChunk()->live;
if (auto *imp = dyn_cast<DefinedImportData>(this))
return imp->file->live;
if (auto *imp = dyn_cast<DefinedImportThunk>(this))
return imp->wrappedSym->file->thunkLive;
// Assume any other kind of symbol is live.
return true;
}
// MinGW specific.
void Symbol::replaceKeepingName(Symbol *Other, size_t Size) {
StringRef OrigName = getName();
memcpy(this, Other, Size);
NameData = OrigName.data();
NameSize = OrigName.size();
void Symbol::replaceKeepingName(Symbol *other, size_t size) {
StringRef origName = getName();
memcpy(this, other, size);
nameData = origName.data();
nameSize = origName.size();
}
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
size_t SymSize = cast<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
if (SymSize == sizeof(coff_symbol16))
return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
assert(SymSize == sizeof(coff_symbol32));
return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize();
if (symSize == sizeof(coff_symbol16))
return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym));
assert(symSize == sizeof(coff_symbol32));
return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym));
}
uint16_t DefinedAbsolute::NumOutputSections;
uint16_t DefinedAbsolute::numOutputSections;
static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
if (Machine == AMD64)
return make<ImportThunkChunkX64>(S);
if (Machine == I386)
return make<ImportThunkChunkX86>(S);
if (Machine == ARM64)
return make<ImportThunkChunkARM64>(S);
assert(Machine == ARMNT);
return make<ImportThunkChunkARM>(S);
static Chunk *makeImportThunk(DefinedImportData *s, uint16_t machine) {
if (machine == AMD64)
return make<ImportThunkChunkX64>(s);
if (machine == I386)
return make<ImportThunkChunkX86>(s);
if (machine == ARM64)
return make<ImportThunkChunkARM64>(s);
assert(machine == ARMNT);
return make<ImportThunkChunkARM>(s);
}
DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
uint16_t Machine)
: Defined(DefinedImportThunkKind, Name), WrappedSym(S),
Data(makeImportThunk(S, Machine)) {}
DefinedImportThunk::DefinedImportThunk(StringRef name, DefinedImportData *s,
uint16_t machine)
: Defined(DefinedImportThunkKind, name), wrappedSym(s),
data(makeImportThunk(s, machine)) {}
Defined *Undefined::getWeakAlias() {
// A weak alias may be a weak alias to another symbol, so check recursively.
for (Symbol *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
if (auto *D = dyn_cast<Defined>(A))
return D;
for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias)
if (auto *d = dyn_cast<Defined>(a))
return d;
return nullptr;
}
} // namespace coff

View File

@ -57,12 +57,12 @@ public:
LastDefinedKind = DefinedSyntheticKind,
};
Kind kind() const { return static_cast<Kind>(SymbolKind); }
Kind kind() const { return static_cast<Kind>(symbolKind); }
// Returns the symbol name.
StringRef getName();
void replaceKeepingName(Symbol *Other, size_t Size);
void replaceKeepingName(Symbol *other, size_t size);
// Returns the file from which this symbol was created.
InputFile *getFile();
@ -73,50 +73,50 @@ public:
protected:
friend SymbolTable;
explicit Symbol(Kind K, StringRef N = "")
: SymbolKind(K), IsExternal(true), IsCOMDAT(false),
WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false),
IsRuntimePseudoReloc(false), NameSize(N.size()),
NameData(N.empty() ? nullptr : N.data()) {}
explicit Symbol(Kind k, StringRef n = "")
: symbolKind(k), isExternal(true), isCOMDAT(false),
writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false),
isRuntimePseudoReloc(false), nameSize(n.size()),
nameData(n.empty() ? nullptr : n.data()) {}
const unsigned SymbolKind : 8;
unsigned IsExternal : 1;
const unsigned symbolKind : 8;
unsigned isExternal : 1;
public:
// This bit is used by the \c DefinedRegular subclass.
unsigned IsCOMDAT : 1;
unsigned isCOMDAT : 1;
// This bit is used by Writer::createSymbolAndStringTable() to prevent
// symbols from being written to the symbol table more than once.
unsigned WrittenToSymtab : 1;
unsigned writtenToSymtab : 1;
// True if this symbol was referenced by a regular (non-bitcode) object.
unsigned IsUsedInRegularObj : 1;
unsigned isUsedInRegularObj : 1;
// True if we've seen both a lazy and an undefined symbol with this symbol
// name, which means that we have enqueued an archive member load and should
// not load any more archive members to resolve the same symbol.
unsigned PendingArchiveLoad : 1;
unsigned pendingArchiveLoad : 1;
/// True if we've already added this symbol to the list of GC roots.
unsigned IsGCRoot : 1;
unsigned isGCRoot : 1;
unsigned IsRuntimePseudoReloc : 1;
unsigned isRuntimePseudoReloc : 1;
protected:
// Symbol name length. Assume symbol lengths fit in a 32-bit integer.
uint32_t NameSize;
uint32_t nameSize;
const char *NameData;
const char *nameData;
};
// The base class for any defined symbols, including absolute symbols,
// etc.
class Defined : public Symbol {
public:
Defined(Kind K, StringRef N) : Symbol(K, N) {}
Defined(Kind k, StringRef n) : Symbol(k, n) {}
static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; }
static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; }
// Returns the RVA (relative virtual address) of this symbol. The
// writer sets and uses RVAs.
@ -135,114 +135,114 @@ class DefinedCOFF : public Defined {
friend Symbol;
public:
DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
: Defined(K, N), File(F), Sym(S) {}
DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s)
: Defined(k, n), file(f), sym(s) {}
static bool classof(const Symbol *S) {
return S->kind() <= LastDefinedCOFFKind;
static bool classof(const Symbol *s) {
return s->kind() <= LastDefinedCOFFKind;
}
InputFile *getFile() { return File; }
InputFile *getFile() { return file; }
COFFSymbolRef getCOFFSymbol();
InputFile *File;
InputFile *file;
protected:
const coff_symbol_generic *Sym;
const coff_symbol_generic *sym;
};
// Regular defined symbols read from object file symbol tables.
class DefinedRegular : public DefinedCOFF {
public:
DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
bool IsExternal = false,
const coff_symbol_generic *S = nullptr,
SectionChunk *C = nullptr)
: DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
this->IsExternal = IsExternal;
this->IsCOMDAT = IsCOMDAT;
DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT,
bool isExternal = false,
const coff_symbol_generic *s = nullptr,
SectionChunk *c = nullptr)
: DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) {
this->isExternal = isExternal;
this->isCOMDAT = isCOMDAT;
}
static bool classof(const Symbol *S) {
return S->kind() == DefinedRegularKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedRegularKind;
}
uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; }
SectionChunk *getChunk() const { return *Data; }
uint32_t getValue() const { return Sym->Value; }
uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; }
SectionChunk *getChunk() const { return *data; }
uint32_t getValue() const { return sym->Value; }
SectionChunk **Data;
SectionChunk **data;
};
class DefinedCommon : public DefinedCOFF {
public:
DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
const coff_symbol_generic *S = nullptr,
CommonChunk *C = nullptr)
: DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
this->IsExternal = true;
DefinedCommon(InputFile *f, StringRef n, uint64_t size,
const coff_symbol_generic *s = nullptr,
CommonChunk *c = nullptr)
: DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) {
this->isExternal = true;
}
static bool classof(const Symbol *S) {
return S->kind() == DefinedCommonKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedCommonKind;
}
uint64_t getRVA() { return Data->getRVA(); }
CommonChunk *getChunk() { return Data; }
uint64_t getRVA() { return data->getRVA(); }
CommonChunk *getChunk() { return data; }
private:
friend SymbolTable;
uint64_t getSize() const { return Size; }
CommonChunk *Data;
uint64_t Size;
uint64_t getSize() const { return size; }
CommonChunk *data;
uint64_t size;
};
// Absolute symbols.
class DefinedAbsolute : public Defined {
public:
DefinedAbsolute(StringRef N, COFFSymbolRef S)
: Defined(DefinedAbsoluteKind, N), VA(S.getValue()) {
IsExternal = S.isExternal();
DefinedAbsolute(StringRef n, COFFSymbolRef s)
: Defined(DefinedAbsoluteKind, n), va(s.getValue()) {
isExternal = s.isExternal();
}
DefinedAbsolute(StringRef N, uint64_t V)
: Defined(DefinedAbsoluteKind, N), VA(V) {}
DefinedAbsolute(StringRef n, uint64_t v)
: Defined(DefinedAbsoluteKind, n), va(v) {}
static bool classof(const Symbol *S) {
return S->kind() == DefinedAbsoluteKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedAbsoluteKind;
}
uint64_t getRVA() { return VA - Config->ImageBase; }
void setVA(uint64_t V) { VA = V; }
uint64_t getRVA() { return va - config->imageBase; }
void setVA(uint64_t v) { va = v; }
// Section index relocations against absolute symbols resolve to
// this 16 bit number, and it is the largest valid section index
// plus one. This variable keeps it.
static uint16_t NumOutputSections;
static uint16_t numOutputSections;
private:
uint64_t VA;
uint64_t va;
};
// This symbol is used for linker-synthesized symbols like __ImageBase and
// __safe_se_handler_table.
class DefinedSynthetic : public Defined {
public:
explicit DefinedSynthetic(StringRef Name, Chunk *C)
: Defined(DefinedSyntheticKind, Name), C(C) {}
explicit DefinedSynthetic(StringRef name, Chunk *c)
: Defined(DefinedSyntheticKind, name), c(c) {}
static bool classof(const Symbol *S) {
return S->kind() == DefinedSyntheticKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedSyntheticKind;
}
// A null chunk indicates that this is __ImageBase. Otherwise, this is some
// other synthesized chunk, like SEHTableChunk.
uint32_t getRVA() { return C ? C->getRVA() : 0; }
Chunk *getChunk() { return C; }
uint32_t getRVA() { return c ? c->getRVA() : 0; }
Chunk *getChunk() { return c; }
private:
Chunk *C;
Chunk *c;
};
// This class represents a symbol defined in an archive file. It is
@ -252,32 +252,32 @@ private:
// the same name, it will ask the Lazy to load a file.
class Lazy : public Symbol {
public:
Lazy(ArchiveFile *F, const Archive::Symbol S)
: Symbol(LazyKind, S.getName()), File(F), Sym(S) {}
Lazy(ArchiveFile *f, const Archive::Symbol s)
: Symbol(LazyKind, s.getName()), file(f), sym(s) {}
static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
ArchiveFile *File;
ArchiveFile *file;
private:
friend SymbolTable;
private:
const Archive::Symbol Sym;
const Archive::Symbol sym;
};
// Undefined symbols.
class Undefined : public Symbol {
public:
explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {}
explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {}
static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; }
static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
// An undefined symbol can have a fallback symbol which gives an
// undefined symbol a second chance if it would remain undefined.
// If it remains undefined, it'll be replaced with whatever the
// Alias pointer points to.
Symbol *WeakAlias = nullptr;
Symbol *weakAlias = nullptr;
// If this symbol is external weak, try to resolve it to a defined
// symbol by searching the chain of fallback symbols. Returns the symbol if
@ -293,23 +293,23 @@ public:
// table in an output. The former has "__imp_" prefix.
class DefinedImportData : public Defined {
public:
DefinedImportData(StringRef N, ImportFile *F)
: Defined(DefinedImportDataKind, N), File(F) {
DefinedImportData(StringRef n, ImportFile *f)
: Defined(DefinedImportDataKind, n), file(f) {
}
static bool classof(const Symbol *S) {
return S->kind() == DefinedImportDataKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedImportDataKind;
}
uint64_t getRVA() { return File->Location->getRVA(); }
Chunk *getChunk() { return File->Location; }
void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }
uint64_t getRVA() { return file->location->getRVA(); }
Chunk *getChunk() { return file->location; }
void setLocation(Chunk *addressTable) { file->location = addressTable; }
StringRef getDLLName() { return File->DLLName; }
StringRef getExternalName() { return File->ExternalName; }
uint16_t getOrdinal() { return File->Hdr->OrdinalHint; }
StringRef getDLLName() { return file->dllName; }
StringRef getExternalName() { return file->externalName; }
uint16_t getOrdinal() { return file->hdr->OrdinalHint; }
ImportFile *File;
ImportFile *file;
};
// This class represents a symbol for a jump table entry which jumps
@ -319,19 +319,19 @@ public:
// a regular name. A function pointer is given as a DefinedImportData.
class DefinedImportThunk : public Defined {
public:
DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine);
DefinedImportThunk(StringRef name, DefinedImportData *s, uint16_t machine);
static bool classof(const Symbol *S) {
return S->kind() == DefinedImportThunkKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedImportThunkKind;
}
uint64_t getRVA() { return Data->getRVA(); }
Chunk *getChunk() { return Data; }
uint64_t getRVA() { return data->getRVA(); }
Chunk *getChunk() { return data; }
DefinedImportData *WrappedSym;
DefinedImportData *wrappedSym;
private:
Chunk *Data;
Chunk *data;
};
// If you have a symbol "foo" in your object file, a symbol name
@ -341,18 +341,18 @@ private:
// This is here just for compatibility with MSVC.
class DefinedLocalImport : public Defined {
public:
DefinedLocalImport(StringRef N, Defined *S)
: Defined(DefinedLocalImportKind, N), Data(make<LocalImportChunk>(S)) {}
DefinedLocalImport(StringRef n, Defined *s)
: Defined(DefinedLocalImportKind, n), data(make<LocalImportChunk>(s)) {}
static bool classof(const Symbol *S) {
return S->kind() == DefinedLocalImportKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedLocalImportKind;
}
uint64_t getRVA() { return Data->getRVA(); }
Chunk *getChunk() { return Data; }
uint64_t getRVA() { return data->getRVA(); }
Chunk *getChunk() { return data; }
private:
LocalImportChunk *Data;
LocalImportChunk *data;
};
inline uint64_t Defined::getRVA() {
@ -405,19 +405,19 @@ inline Chunk *Defined::getChunk() {
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
alignas(DefinedRegular) char A[sizeof(DefinedRegular)];
alignas(DefinedCommon) char B[sizeof(DefinedCommon)];
alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)];
alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)];
alignas(Lazy) char E[sizeof(Lazy)];
alignas(Undefined) char F[sizeof(Undefined)];
alignas(DefinedImportData) char G[sizeof(DefinedImportData)];
alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)];
alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)];
alignas(DefinedRegular) char a[sizeof(DefinedRegular)];
alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
alignas(Lazy) char e[sizeof(Lazy)];
alignas(Undefined) char f[sizeof(Undefined)];
alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
};
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
void replaceSymbol(Symbol *s, ArgT &&... arg) {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
@ -425,11 +425,11 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
new (S) T(std::forward<ArgT>(Arg)...);
new (s) T(std::forward<ArgT>(arg)...);
}
} // namespace coff
std::string toString(coff::Symbol &B);
std::string toString(coff::Symbol &b);
} // namespace lld
#endif

View File

@ -19,44 +19,44 @@ namespace coff {
class TypeMerger {
public:
TypeMerger(llvm::BumpPtrAllocator &Alloc)
: TypeTable(Alloc), IDTable(Alloc), GlobalTypeTable(Alloc),
GlobalIDTable(Alloc) {}
TypeMerger(llvm::BumpPtrAllocator &alloc)
: typeTable(alloc), iDTable(alloc), globalTypeTable(alloc),
globalIDTable(alloc) {}
/// Get the type table or the global type table if /DEBUG:GHASH is enabled.
inline llvm::codeview::TypeCollection &getTypeTable() {
if (Config->DebugGHashes)
return GlobalTypeTable;
return TypeTable;
if (config->debugGHashes)
return globalTypeTable;
return typeTable;
}
/// Get the ID table or the global ID table if /DEBUG:GHASH is enabled.
inline llvm::codeview::TypeCollection &getIDTable() {
if (Config->DebugGHashes)
return GlobalIDTable;
return IDTable;
if (config->debugGHashes)
return globalIDTable;
return iDTable;
}
/// Type records that will go into the PDB TPI stream.
llvm::codeview::MergingTypeTableBuilder TypeTable;
llvm::codeview::MergingTypeTableBuilder typeTable;
/// Item records that will go into the PDB IPI stream.
llvm::codeview::MergingTypeTableBuilder IDTable;
llvm::codeview::MergingTypeTableBuilder iDTable;
/// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH)
llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
llvm::codeview::GlobalTypeTableBuilder globalTypeTable;
/// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH)
llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
llvm::codeview::GlobalTypeTableBuilder globalIDTable;
};
/// Map from type index and item index in a type server PDB to the
/// corresponding index in the destination PDB.
struct CVIndexMap {
llvm::SmallVector<llvm::codeview::TypeIndex, 0> TPIMap;
llvm::SmallVector<llvm::codeview::TypeIndex, 0> IPIMap;
bool IsTypeServerMap = false;
bool IsPrecompiledTypeMap = false;
llvm::SmallVector<llvm::codeview::TypeIndex, 0> tpiMap;
llvm::SmallVector<llvm::codeview::TypeIndex, 0> ipiMap;
bool isTypeServerMap = false;
bool isPrecompiledTypeMap = false;
};
} // namespace coff

File diff suppressed because it is too large Load Diff

View File

@ -18,17 +18,17 @@
namespace lld {
namespace coff {
static const int PageSize = 4096;
static const int pageSize = 4096;
void writeResult();
class PartialSection {
public:
PartialSection(StringRef N, uint32_t Chars)
: Name(N), Characteristics(Chars) {}
StringRef Name;
unsigned Characteristics;
std::vector<Chunk *> Chunks;
PartialSection(StringRef n, uint32_t chars)
: name(n), characteristics(chars) {}
StringRef name;
unsigned characteristics;
std::vector<Chunk *> chunks;
};
// OutputSection represents a section in an output file. It's a
@ -38,45 +38,45 @@ public:
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) {
Header.Characteristics = Chars;
OutputSection(llvm::StringRef n, uint32_t chars) : name(n) {
header.Characteristics = chars;
}
void addChunk(Chunk *C);
void insertChunkAtStart(Chunk *C);
void merge(OutputSection *Other);
void setPermissions(uint32_t C);
uint64_t getRVA() { return Header.VirtualAddress; }
uint64_t getFileOff() { return Header.PointerToRawData; }
void writeHeaderTo(uint8_t *Buf);
void addContributingPartialSection(PartialSection *Sec);
void addChunk(Chunk *c);
void insertChunkAtStart(Chunk *c);
void merge(OutputSection *other);
void setPermissions(uint32_t c);
uint64_t getRVA() { return header.VirtualAddress; }
uint64_t getFileOff() { return header.PointerToRawData; }
void writeHeaderTo(uint8_t *buf);
void addContributingPartialSection(PartialSection *sec);
// Returns the size of this section in an executable memory image.
// This may be smaller than the raw size (the raw size is multiple
// of disk sector size, so there may be padding at end), or may be
// larger (if that's the case, the loader reserves spaces after end
// of raw data).
uint64_t getVirtualSize() { return Header.VirtualSize; }
uint64_t getVirtualSize() { return header.VirtualSize; }
// Returns the size of the section in the output file.
uint64_t getRawSize() { return Header.SizeOfRawData; }
uint64_t getRawSize() { return header.SizeOfRawData; }
// Set offset into the string table storing this section name.
// Used only when the name is longer than 8 bytes.
void setStringTableOff(uint32_t V) { StringTableOff = V; }
void setStringTableOff(uint32_t v) { stringTableOff = v; }
// N.B. The section index is one based.
uint32_t SectionIndex = 0;
uint32_t sectionIndex = 0;
llvm::StringRef Name;
llvm::object::coff_section Header = {};
llvm::StringRef name;
llvm::object::coff_section header = {};
std::vector<Chunk *> Chunks;
std::vector<Chunk *> OrigChunks;
std::vector<Chunk *> chunks;
std::vector<Chunk *> origChunks;
std::vector<PartialSection *> ContribSections;
std::vector<PartialSection *> contribSections;
private:
uint32_t StringTableOff = 0;
uint32_t stringTableOff = 0;
};
} // namespace coff

View File

@ -19,64 +19,64 @@ using namespace lld;
// TODO(sbc): Remove this once CGOptLevel can be set completely based on bitcode
// function metadata.
CodeGenOpt::Level lld::args::getCGOptLevel(int OptLevelLTO) {
if (OptLevelLTO == 3)
CodeGenOpt::Level lld::args::getCGOptLevel(int optLevelLTO) {
if (optLevelLTO == 3)
return CodeGenOpt::Aggressive;
assert(OptLevelLTO < 3);
assert(optLevelLTO < 3);
return CodeGenOpt::Default;
}
int64_t lld::args::getInteger(opt::InputArgList &Args, unsigned Key,
int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key,
int64_t Default) {
auto *A = Args.getLastArg(Key);
if (!A)
auto *a = args.getLastArg(key);
if (!a)
return Default;
int64_t V;
if (to_integer(A->getValue(), V, 10))
return V;
int64_t v;
if (to_integer(a->getValue(), v, 10))
return v;
StringRef Spelling = Args.getArgString(A->getIndex());
error(Spelling + ": number expected, but got '" + A->getValue() + "'");
StringRef spelling = args.getArgString(a->getIndex());
error(spelling + ": number expected, but got '" + a->getValue() + "'");
return 0;
}
std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
std::vector<StringRef> V;
for (auto *Arg : Args.filtered(Id))
V.push_back(Arg->getValue());
return V;
std::vector<StringRef> lld::args::getStrings(opt::InputArgList &args, int id) {
std::vector<StringRef> v;
for (auto *arg : args.filtered(id))
v.push_back(arg->getValue());
return v;
}
uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id,
StringRef Key, uint64_t Default) {
for (auto *Arg : Args.filtered_reverse(Id)) {
std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
if (KV.first == Key) {
uint64_t Result = Default;
if (!to_integer(KV.second, Result))
error("invalid " + Key + ": " + KV.second);
return Result;
uint64_t lld::args::getZOptionValue(opt::InputArgList &args, int id,
StringRef key, uint64_t Default) {
for (auto *arg : args.filtered_reverse(id)) {
std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
if (kv.first == key) {
uint64_t result = Default;
if (!to_integer(kv.second, result))
error("invalid " + key + ": " + kv.second);
return result;
}
}
return Default;
}
std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) {
SmallVector<StringRef, 0> Arr;
MB.getBuffer().split(Arr, '\n');
std::vector<StringRef> lld::args::getLines(MemoryBufferRef mb) {
SmallVector<StringRef, 0> arr;
mb.getBuffer().split(arr, '\n');
std::vector<StringRef> Ret;
for (StringRef S : Arr) {
S = S.trim();
if (!S.empty() && S[0] != '#')
Ret.push_back(S);
std::vector<StringRef> ret;
for (StringRef s : arr) {
s = s.trim();
if (!s.empty() && s[0] != '#')
ret.push_back(s);
}
return Ret;
return ret;
}
StringRef lld::args::getFilenameWithoutExe(StringRef Path) {
if (Path.endswith_lower(".exe"))
return sys::path::stem(Path);
return sys::path::filename(Path);
StringRef lld::args::getFilenameWithoutExe(StringRef path) {
if (path.endswith_lower(".exe"))
return sys::path::stem(path);
return sys::path::filename(path);
}

View File

@ -26,29 +26,29 @@ using namespace lld;
// The functions defined in this file can be called from multiple threads,
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
static std::mutex mu;
// Prints "\n" or does nothing, depending on Msg contents of
// the previous call of this function.
static void newline(raw_ostream *ErrorOS, const Twine &Msg) {
static void newline(raw_ostream *errorOS, const Twine &msg) {
// True if the previous error message contained "\n".
// We want to separate multi-line error messages with a newline.
static bool Flag;
static bool flag;
if (Flag)
*ErrorOS << "\n";
Flag = StringRef(Msg.str()).contains('\n');
if (flag)
*errorOS << "\n";
flag = StringRef(msg.str()).contains('\n');
}
ErrorHandler &lld::errorHandler() {
static ErrorHandler Handler;
return Handler;
static ErrorHandler handler;
return handler;
}
void lld::exitLld(int Val) {
void lld::exitLld(int val) {
// Delete any temporary file, while keeping the memory mapping open.
if (errorHandler().OutputBuffer)
errorHandler().OutputBuffer->discard();
if (errorHandler().outputBuffer)
errorHandler().outputBuffer->discard();
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
@ -57,87 +57,87 @@ void lld::exitLld(int Val) {
outs().flush();
errs().flush();
_exit(Val);
_exit(val);
}
void lld::diagnosticHandler(const DiagnosticInfo &DI) {
SmallString<128> S;
raw_svector_ostream OS(S);
DiagnosticPrinterRawOStream DP(OS);
DI.print(DP);
switch (DI.getSeverity()) {
void lld::diagnosticHandler(const DiagnosticInfo &di) {
SmallString<128> s;
raw_svector_ostream os(s);
DiagnosticPrinterRawOStream dp(os);
di.print(dp);
switch (di.getSeverity()) {
case DS_Error:
error(S);
error(s);
break;
case DS_Warning:
warn(S);
warn(s);
break;
case DS_Remark:
case DS_Note:
message(S);
message(s);
break;
}
}
void lld::checkError(Error E) {
handleAllErrors(std::move(E),
[&](ErrorInfoBase &EIB) { error(EIB.message()); });
void lld::checkError(Error e) {
handleAllErrors(std::move(e),
[&](ErrorInfoBase &eib) { error(eib.message()); });
}
void ErrorHandler::print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << LogName << ": ";
if (ColorDiagnostics) {
ErrorOS->changeColor(C, true);
*ErrorOS << S;
ErrorOS->resetColor();
void ErrorHandler::print(StringRef s, raw_ostream::Colors c) {
*errorOS << logName << ": ";
if (colorDiagnostics) {
errorOS->changeColor(c, true);
*errorOS << s;
errorOS->resetColor();
} else {
*ErrorOS << S;
*errorOS << s;
}
}
void ErrorHandler::log(const Twine &Msg) {
if (Verbose) {
std::lock_guard<std::mutex> Lock(Mu);
*ErrorOS << LogName << ": " << Msg << "\n";
void ErrorHandler::log(const Twine &msg) {
if (verbose) {
std::lock_guard<std::mutex> lock(mu);
*errorOS << logName << ": " << msg << "\n";
}
}
void ErrorHandler::message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Msg << "\n";
void ErrorHandler::message(const Twine &msg) {
std::lock_guard<std::mutex> lock(mu);
outs() << msg << "\n";
outs().flush();
}
void ErrorHandler::warn(const Twine &Msg) {
if (FatalWarnings) {
error(Msg);
void ErrorHandler::warn(const Twine &msg) {
if (fatalWarnings) {
error(msg);
return;
}
std::lock_guard<std::mutex> Lock(Mu);
newline(ErrorOS, Msg);
std::lock_guard<std::mutex> lock(mu);
newline(errorOS, msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
*errorOS << msg << "\n";
}
void ErrorHandler::error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
newline(ErrorOS, Msg);
void ErrorHandler::error(const Twine &msg) {
std::lock_guard<std::mutex> lock(mu);
newline(errorOS, msg);
if (ErrorLimit == 0 || ErrorCount < ErrorLimit) {
if (errorLimit == 0 || errorCount < errorLimit) {
print("error: ", raw_ostream::RED);
*ErrorOS << Msg << "\n";
} else if (ErrorCount == ErrorLimit) {
*errorOS << msg << "\n";
} else if (errorCount == errorLimit) {
print("error: ", raw_ostream::RED);
*ErrorOS << ErrorLimitExceededMsg << "\n";
if (ExitEarly)
*errorOS << errorLimitExceededMsg << "\n";
if (exitEarly)
exitLld(1);
}
++ErrorCount;
++errorCount;
}
void ErrorHandler::fatal(const Twine &Msg) {
error(Msg);
void ErrorHandler::fatal(const Twine &msg) {
error(msg);
exitLld(1);
}

View File

@ -38,43 +38,43 @@ using namespace lld;
//
// This function spawns a background thread to remove the file.
// The calling thread returns almost immediately.
void lld::unlinkAsync(StringRef Path) {
void lld::unlinkAsync(StringRef path) {
// Removing a file is async on windows.
#if defined(_WIN32)
sys::fs::remove(Path);
#else
if (!ThreadsEnabled || !sys::fs::exists(Path) ||
!sys::fs::is_regular_file(Path))
if (!threadsEnabled || !sys::fs::exists(path) ||
!sys::fs::is_regular_file(path))
return;
// We cannot just remove path from a different thread because we are now going
// to create path as a new file.
// Instead we open the file and unlink it on this thread. The unlink is fast
// since the open fd guarantees that it is not removing the last reference.
int FD;
std::error_code EC = sys::fs::openFileForRead(Path, FD);
sys::fs::remove(Path);
int fd;
std::error_code ec = sys::fs::openFileForRead(path, fd);
sys::fs::remove(path);
if (EC)
if (ec)
return;
// close and therefore remove TempPath in background.
std::mutex M;
std::condition_variable CV;
bool Started = false;
std::thread([&, FD] {
std::mutex m;
std::condition_variable cv;
bool started = false;
std::thread([&, fd] {
{
std::lock_guard<std::mutex> L(M);
Started = true;
CV.notify_all();
std::lock_guard<std::mutex> l(m);
started = true;
cv.notify_all();
}
::close(FD);
::close(fd);
}).detach();
// GLIBC 2.26 and earlier have race condition that crashes an entire process
// if the main thread calls exit(2) while other thread is starting up.
std::unique_lock<std::mutex> L(M);
CV.wait(L, [&] { return Started; });
std::unique_lock<std::mutex> l(m);
cv.wait(l, [&] { return started; });
#endif
}
@ -90,10 +90,10 @@ void lld::unlinkAsync(StringRef Path) {
// FileOutputBuffer doesn't touch a desitnation file until commit()
// is called. We use that class without calling commit() to predict
// if the given file is writable.
std::error_code lld::tryCreateFile(StringRef Path) {
if (Path.empty())
std::error_code lld::tryCreateFile(StringRef path) {
if (path.empty())
return std::error_code();
if (Path == "-")
if (path == "-")
return std::error_code();
return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError());
}

View File

@ -11,12 +11,12 @@
using namespace llvm;
using namespace lld;
BumpPtrAllocator lld::BAlloc;
StringSaver lld::Saver{BAlloc};
std::vector<SpecificAllocBase *> lld::SpecificAllocBase::Instances;
BumpPtrAllocator lld::bAlloc;
StringSaver lld::saver{bAlloc};
std::vector<SpecificAllocBase *> lld::SpecificAllocBase::instances;
void lld::freeArena() {
for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
Alloc->reset();
BAlloc.Reset();
for (SpecificAllocBase *alloc : SpecificAllocBase::instances)
alloc->reset();
bAlloc.Reset();
}

View File

@ -21,41 +21,41 @@ using namespace llvm::sys;
// assuming that the current directory is "/home/john/bar".
// Returned string is a forward slash separated path even on Windows to avoid
// a mess with backslash-as-escape and backslash-as-path-separator.
std::string lld::relativeToRoot(StringRef Path) {
SmallString<128> Abs = Path;
if (fs::make_absolute(Abs))
return Path;
path::remove_dots(Abs, /*remove_dot_dot=*/true);
std::string lld::relativeToRoot(StringRef path) {
SmallString<128> abs = path;
if (fs::make_absolute(abs))
return path;
path::remove_dots(abs, /*remove_dot_dot=*/true);
// This is Windows specific. root_name() returns a drive letter
// (e.g. "c:") or a UNC name (//net). We want to keep it as part
// of the result.
SmallString<128> Res;
StringRef Root = path::root_name(Abs);
if (Root.endswith(":"))
Res = Root.drop_back();
else if (Root.startswith("//"))
Res = Root.substr(2);
SmallString<128> res;
StringRef root = path::root_name(abs);
if (root.endswith(":"))
res = root.drop_back();
else if (root.startswith("//"))
res = root.substr(2);
path::append(Res, path::relative_path(Abs));
return path::convert_to_slash(Res);
path::append(res, path::relative_path(abs));
return path::convert_to_slash(res);
}
// Quote a given string if it contains a space character.
std::string lld::quote(StringRef S) {
if (S.contains(' '))
return ("\"" + S + "\"").str();
return S;
std::string lld::quote(StringRef s) {
if (s.contains(' '))
return ("\"" + s + "\"").str();
return s;
}
// Converts an Arg to a string representation suitable for a response file.
// To show an Arg in a diagnostic, use Arg::getAsString() instead.
std::string lld::toString(const opt::Arg &Arg) {
std::string K = Arg.getSpelling();
if (Arg.getNumValues() == 0)
return K;
std::string V = quote(Arg.getValue());
if (Arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
return K + V;
return K + " " + V;
std::string lld::toString(const opt::Arg &arg) {
std::string k = arg.getSpelling();
if (arg.getNumValues() == 0)
return k;
std::string v = quote(arg.getValue());
if (arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
return k + v;
return k + " " + v;
}

View File

@ -19,85 +19,85 @@ using namespace llvm;
using namespace lld;
// Returns the demangled C++ symbol name for Name.
Optional<std::string> lld::demangleItanium(StringRef Name) {
Optional<std::string> lld::demangleItanium(StringRef name) {
// itaniumDemangle can be used to demangle strings other than symbol
// names which do not necessarily start with "_Z". Name can be
// either a C or C++ symbol. Don't call itaniumDemangle if the name
// does not look like a C++ symbol name to avoid getting unexpected
// result for a C symbol that happens to match a mangled type name.
if (!Name.startswith("_Z"))
if (!name.startswith("_Z"))
return None;
char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
if (!Buf)
char *buf = itaniumDemangle(name.str().c_str(), nullptr, nullptr, nullptr);
if (!buf)
return None;
std::string S(Buf);
free(Buf);
return S;
std::string s(buf);
free(buf);
return s;
}
Optional<std::string> lld::demangleMSVC(StringRef Name) {
std::string Prefix;
if (Name.consume_front("__imp_"))
Prefix = "__declspec(dllimport) ";
Optional<std::string> lld::demangleMSVC(StringRef name) {
std::string prefix;
if (name.consume_front("__imp_"))
prefix = "__declspec(dllimport) ";
// Demangle only C++ names.
if (!Name.startswith("?"))
if (!name.startswith("?"))
return None;
char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
if (!Buf)
char *buf = microsoftDemangle(name.str().c_str(), nullptr, nullptr, nullptr);
if (!buf)
return None;
std::string S(Buf);
free(Buf);
return Prefix + S;
std::string s(buf);
free(buf);
return prefix + s;
}
StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
for (StringRef S : Pat) {
Expected<GlobPattern> Pat = GlobPattern::create(S);
if (!Pat)
error(toString(Pat.takeError()));
StringMatcher::StringMatcher(ArrayRef<StringRef> pat) {
for (StringRef s : pat) {
Expected<GlobPattern> pat = GlobPattern::create(s);
if (!pat)
error(toString(pat.takeError()));
else
Patterns.push_back(*Pat);
patterns.push_back(*pat);
}
}
bool StringMatcher::match(StringRef S) const {
for (const GlobPattern &Pat : Patterns)
if (Pat.match(S))
bool StringMatcher::match(StringRef s) const {
for (const GlobPattern &pat : patterns)
if (pat.match(s))
return true;
return false;
}
// Converts a hex string (e.g. "deadbeef") to a vector.
std::vector<uint8_t> lld::parseHex(StringRef S) {
std::vector<uint8_t> Hex;
while (!S.empty()) {
StringRef B = S.substr(0, 2);
S = S.substr(2);
uint8_t H;
if (!to_integer(B, H, 16)) {
error("not a hexadecimal value: " + B);
std::vector<uint8_t> lld::parseHex(StringRef s) {
std::vector<uint8_t> hex;
while (!s.empty()) {
StringRef b = s.substr(0, 2);
s = s.substr(2);
uint8_t h;
if (!to_integer(b, h, 16)) {
error("not a hexadecimal value: " + b);
return {};
}
Hex.push_back(H);
hex.push_back(h);
}
return Hex;
return hex;
}
// Returns true if S is valid as a C language identifier.
bool lld::isValidCIdentifier(StringRef S) {
return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
std::all_of(S.begin() + 1, S.end(),
[](char C) { return C == '_' || isAlnum(C); });
bool lld::isValidCIdentifier(StringRef s) {
return !s.empty() && (isAlpha(s[0]) || s[0] == '_') &&
std::all_of(s.begin() + 1, s.end(),
[](char c) { return c == '_' || isAlnum(c); });
}
// Write the contents of the a buffer to a file
void lld::saveBuffer(StringRef Buffer, const Twine &Path) {
std::error_code EC;
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
if (EC)
error("cannot create " + Path + ": " + EC.message());
OS << Buffer;
void lld::saveBuffer(StringRef buffer, const Twine &path) {
std::error_code ec;
raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::F_None);
if (ec)
error("cannot create " + path + ": " + ec.message());
os << buffer;
}

View File

@ -8,4 +8,4 @@
#include "lld/Common/Threads.h"
bool lld::ThreadsEnabled = true;
bool lld::threadsEnabled = true;

View File

@ -13,43 +13,43 @@
using namespace lld;
using namespace llvm;
ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); }
ScopedTimer::ScopedTimer(Timer &t) : t(&t) { t.start(); }
void ScopedTimer::stop() {
if (!T)
if (!t)
return;
T->stop();
T = nullptr;
t->stop();
t = nullptr;
}
ScopedTimer::~ScopedTimer() { stop(); }
Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {}
Timer::Timer(llvm::StringRef Name, Timer &Parent)
: Name(Name), Parent(&Parent) {}
Timer::Timer(llvm::StringRef name) : name(name), parent(nullptr) {}
Timer::Timer(llvm::StringRef name, Timer &parent)
: name(name), parent(&parent) {}
void Timer::start() {
if (Parent && Total.count() == 0)
Parent->Children.push_back(this);
StartTime = std::chrono::high_resolution_clock::now();
if (parent && total.count() == 0)
parent->children.push_back(this);
startTime = std::chrono::high_resolution_clock::now();
}
void Timer::stop() {
Total += (std::chrono::high_resolution_clock::now() - StartTime);
total += (std::chrono::high_resolution_clock::now() - startTime);
}
Timer &Timer::root() {
static Timer RootTimer("Total Link Time");
return RootTimer;
static Timer rootTimer("Total Link Time");
return rootTimer;
}
void Timer::print() {
double TotalDuration = static_cast<double>(root().millis());
double totalDuration = static_cast<double>(root().millis());
// We want to print the grand total under all the intermediate phases, so we
// print all children first, then print the total under that.
for (const auto &Child : Children)
Child->print(1, TotalDuration);
for (const auto &child : children)
child->print(1, totalDuration);
message(std::string(49, '-'));
@ -58,22 +58,22 @@ void Timer::print() {
double Timer::millis() const {
return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
Total)
total)
.count();
}
void Timer::print(int Depth, double TotalDuration, bool Recurse) const {
double P = 100.0 * millis() / TotalDuration;
void Timer::print(int depth, double totalDuration, bool recurse) const {
double p = 100.0 * millis() / totalDuration;
SmallString<32> Str;
llvm::raw_svector_ostream Stream(Str);
std::string S = std::string(Depth * 2, ' ') + Name + std::string(":");
Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P);
SmallString<32> str;
llvm::raw_svector_ostream stream(str);
std::string s = std::string(depth * 2, ' ') + name + std::string(":");
stream << format("%-30s%5d ms (%5.1f%%)", s.c_str(), (int)millis(), p);
message(Str);
message(str);
if (Recurse) {
for (const auto &Child : Children)
Child->print(Depth + 1, TotalDuration);
if (recurse) {
for (const auto &child : children)
child->print(depth + 1, totalDuration);
}
}

View File

@ -398,9 +398,9 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off)
patchee(p), patcheeOffset(off) {
this->parent = p->getParent();
patchSym = addSyntheticLocal(
Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0,
saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0,
getSize(), *this);
addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this);
addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this);
}
uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
@ -485,8 +485,8 @@ void AArch64Err843419Patcher::init() {
void AArch64Err843419Patcher::insertPatches(
InputSectionDescription &isd, std::vector<Patch843419Section *> &patches) {
uint64_t isecLimit;
uint64_t prevISLimit = isd.sections.front()->outSecOff;
uint64_t patchUpperBound = prevISLimit + target->getThunkSectionSpacing();
uint64_t prevIsecLimit = isd.sections.front()->outSecOff;
uint64_t patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing();
uint64_t outSecAddr = isd.sections.front()->getParent()->addr;
// Set the OutSecOff of patches to the place where we want to insert them.
@ -498,14 +498,14 @@ void AArch64Err843419Patcher::insertPatches(
isecLimit = isec->outSecOff + isec->getSize();
if (isecLimit > patchUpperBound) {
while (patchIt != patchEnd) {
if ((*patchIt)->getLDSTAddr() - outSecAddr >= prevISLimit)
if ((*patchIt)->getLDSTAddr() - outSecAddr >= prevIsecLimit)
break;
(*patchIt)->outSecOff = prevISLimit;
(*patchIt)->outSecOff = prevIsecLimit;
++patchIt;
}
patchUpperBound = prevISLimit + target->getThunkSectionSpacing();
patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing();
}
prevISLimit = isecLimit;
prevIsecLimit = isecLimit;
}
for (; patchIt != patchEnd; ++patchIt) {
(*patchIt)->outSecOff = isecLimit;

View File

@ -76,13 +76,13 @@ static void readConfigs(opt::InputArgList &args);
bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
raw_ostream &error) {
errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
errorHandler().ErrorLimitExceededMsg =
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
errorHandler().ErrorOS = &error;
errorHandler().ExitEarly = canExitEarly;
errorHandler().ColorDiagnostics = error.has_colors();
errorHandler().errorOS = &error;
errorHandler().exitEarly = canExitEarly;
errorHandler().colorDiagnostics = error.has_colors();
inputSections.clear();
outputSections.clear();
@ -399,7 +399,7 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) {
opt::InputArgList args = parser.parse(argsArr.slice(1));
// Interpret this flag early because error() depends on them.
errorHandler().ErrorLimit = args::getInteger(args, OPT_error_limit, 20);
errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20);
checkZOptions(args);
// Handle -help
@ -783,10 +783,10 @@ static void parseClangOption(StringRef opt, const Twine &msg) {
// Initializes Config members by the command line options.
static void readConfigs(opt::InputArgList &args) {
errorHandler().Verbose = args.hasArg(OPT_verbose);
errorHandler().FatalWarnings =
errorHandler().verbose = args.hasArg(OPT_verbose);
errorHandler().fatalWarnings =
args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
ThreadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
config->allowMultipleDefinition =
args.hasFlag(OPT_allow_multiple_definition,
@ -939,7 +939,7 @@ static void readConfigs(opt::InputArgList &args) {
// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
parseClangOption(Saver.save("-mcpu=" + StringRef(arg->getValue())),
parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
arg->getSpelling());
for (auto *arg : args.filtered(OPT_plugin_opt))
@ -1579,8 +1579,8 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
if (!sym)
continue;
Symbol *real = addUndefined(Saver.save("__real_" + name));
Symbol *wrap = addUndefined(Saver.save("__wrap_" + name));
Symbol *real = addUndefined(saver.save("__real_" + name));
Symbol *wrap = addUndefined(saver.save("__wrap_" + name));
v.push_back({sym, real, wrap});
// We want to tell LTO not to inline symbols to be overwritten

View File

@ -59,15 +59,15 @@ static void handleColorDiagnostics(opt::InputArgList &args) {
if (!arg)
return;
if (arg->getOption().getID() == OPT_color_diagnostics) {
errorHandler().ColorDiagnostics = true;
errorHandler().colorDiagnostics = true;
} else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
errorHandler().ColorDiagnostics = false;
errorHandler().colorDiagnostics = false;
} else {
StringRef s = arg->getValue();
if (s == "always")
errorHandler().ColorDiagnostics = true;
errorHandler().colorDiagnostics = true;
else if (s == "never")
errorHandler().ColorDiagnostics = false;
errorHandler().colorDiagnostics = false;
else if (s != "auto")
error("unknown option: --color-diagnostics=" + s);
}
@ -101,7 +101,7 @@ static void concatLTOPluginOptions(SmallVectorImpl<const char *> &args) {
for (size_t i = 0, e = args.size(); i != e; ++i) {
StringRef s = args[i];
if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) {
v.push_back(Saver.save(s + "=" + args[i + 1]).data());
v.push_back(saver.save(s + "=" + args[i + 1]).data());
++i;
} else {
v.push_back(args[i]);
@ -124,7 +124,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(args), vec);
cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec);
concatLTOPluginOptions(vec);
args = this->ParseArgs(vec, missingIndex, missingCount);

View File

@ -392,7 +392,7 @@ template <class ELFT>
void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> fn) {
// If threading is disabled or the number of sections are
// too small to use threading, call Fn sequentially.
if (!ThreadsEnabled || sections.size() < 1024) {
if (!threadsEnabled || sections.size() < 1024) {
forEachClassRange(0, sections.size(), fn);
++cnt;
return;

View File

@ -92,7 +92,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef path) {
// The --chroot option changes our virtual root directory.
// This is useful when you are dealing with files created by --reproduce.
if (!config->chroot.empty() && path.startswith("/"))
path = Saver.save(config->chroot + path);
path = saver.save(config->chroot + path);
log(path);
@ -1366,7 +1366,7 @@ template <class ELFT> void SharedFile::parse() {
reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name;
versionedNameBuffer.clear();
name = (name + "@" + verName).toStringRef(versionedNameBuffer);
symtab->addSymbol(SharedSymbol{*this, Saver.save(name), sym.getBinding(),
symtab->addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(),
sym.st_other, sym.getType(), sym.st_value,
sym.st_size, alignment, idx});
}
@ -1432,8 +1432,8 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
// symbols later in the link stage). So we append file offset to make
// filename unique.
StringRef name = archiveName.empty()
? Saver.save(path)
: Saver.save(archiveName + "(" + path + " at " +
? saver.save(path)
: saver.save(archiveName + "(" + path + " at " +
utostr(offsetInArchive) + ")");
MemoryBufferRef mbref(mb.getBuffer(), name);
@ -1460,7 +1460,7 @@ template <class ELFT>
static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
const lto::InputFile::Symbol &objSym,
BitcodeFile &f) {
StringRef name = Saver.save(objSym.getName());
StringRef name = saver.save(objSym.getName());
uint8_t binding = objSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t type = objSym.isTLS() ? STT_TLS : STT_NOTYPE;
uint8_t visibility = mapVisibility(objSym.getVisibility());
@ -1513,11 +1513,11 @@ void BinaryFile::parse() {
if (!isAlnum(s[i]))
s[i] = '_';
symtab->addSymbol(Defined{nullptr, Saver.save(s + "_start"), STB_GLOBAL,
symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, 0, 0, section});
symtab->addSymbol(Defined{nullptr, Saver.save(s + "_end"), STB_GLOBAL,
symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, data.size(), 0, section});
symtab->addSymbol(Defined{nullptr, Saver.save(s + "_size"), STB_GLOBAL,
symtab->addSymbol(Defined{nullptr, saver.save(s + "_size"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr});
}
@ -1566,7 +1566,7 @@ template <class ELFT> void LazyObjFile::parse() {
for (const lto::InputFile::Symbol &sym : obj->symbols()) {
if (sym.isUndefined())
continue;
symtab->addSymbol(LazyObject{*this, Saver.save(sym.getName())});
symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())});
}
return;
}

View File

@ -148,7 +148,7 @@ void InputSectionBase::uncompress() const {
{
static std::mutex mu;
std::lock_guard<std::mutex> lock(mu);
uncompressedBuf = BAlloc.Allocate<char>(size);
uncompressedBuf = bAlloc.Allocate<char>(size);
}
if (Error e = zlib::uncompress(toStringRef(rawData), uncompressedBuf, size))
@ -231,7 +231,7 @@ void InputSectionBase::parseCompressedHeader() {
// Restore the original section name.
// (e.g. ".zdebug_info" -> ".debug_info")
name = Saver.save("." + name.substr(2));
name = saver.save("." + name.substr(2));
return;
}

View File

@ -260,8 +260,8 @@ template <class ELFT> void MarkLive<ELFT>::run() {
if (isReserved(sec) || script->shouldKeep(sec)) {
enqueue(sec, 0);
} else if (isValidCIdentifier(sec->name)) {
cNamedSections[Saver.save("__start_" + sec->name)].push_back(sec);
cNamedSections[Saver.save("__stop_" + sec->name)].push_back(sec);
cNamedSections[saver.save("__start_" + sec->name)].push_back(sec);
cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec);
}
}

View File

@ -1639,18 +1639,18 @@ void ThunkCreator::createInitialThunkSections(
lastThunkLowerBound = isdEnd - thunkSectionSpacing;
uint32_t isecLimit;
uint32_t prevISLimit = isdBegin;
uint32_t prevIsecLimit = isdBegin;
uint32_t thunkUpperBound = isdBegin + thunkSectionSpacing;
for (const InputSection *isec : isd->sections) {
isecLimit = isec->outSecOff + isec->getSize();
if (isecLimit > thunkUpperBound) {
addThunkSection(os, isd, prevISLimit);
thunkUpperBound = prevISLimit + thunkSectionSpacing;
addThunkSection(os, isd, prevIsecLimit);
thunkUpperBound = prevIsecLimit + thunkSectionSpacing;
}
if (isecLimit > lastThunkLowerBound)
break;
prevISLimit = isecLimit;
prevIsecLimit = isecLimit;
}
addThunkSection(os, isd, isecLimit);
});

View File

@ -280,7 +280,7 @@ void ScriptParser::addFile(StringRef s) {
SmallString<128> pathData;
StringRef path = (config->sysroot + s).toStringRef(pathData);
if (sys::fs::exists(path)) {
driver->addFile(Saver.save(path), /*WithLOption=*/false);
driver->addFile(saver.save(path), /*WithLOption=*/false);
return;
}
}
@ -291,7 +291,7 @@ void ScriptParser::addFile(StringRef s) {
if (config->sysroot.empty())
driver->addFile(s.substr(1), /*WithLOption=*/false);
else
driver->addFile(Saver.save(config->sysroot + "/" + s.substr(1)),
driver->addFile(saver.save(config->sysroot + "/" + s.substr(1)),
/*WithLOption=*/false);
} else if (s.startswith("-l")) {
driver->addLibrary(s.substr(2));
@ -299,7 +299,7 @@ void ScriptParser::addFile(StringRef s) {
driver->addFile(s, /*WithLOption=*/false);
} else {
if (Optional<std::string> path = findFromSearchPaths(s))
driver->addFile(Saver.save(*path), /*WithLOption=*/true);
driver->addFile(saver.save(*path), /*WithLOption=*/true);
else
setError("unable to find " + s);
}

View File

@ -72,7 +72,7 @@ static ArrayRef<uint8_t> getVersion() {
// This is only for testing.
StringRef s = getenv("LLD_VERSION");
if (s.empty())
s = Saver.save(Twine("Linker: ") + getLLDVersion());
s = saver.save(Twine("Linker: ") + getLLDVersion());
// +1 to include the terminating '\0'.
return {(const uint8_t *)s.data(), s.size() + 1};
@ -254,7 +254,7 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
InputSection *elf::createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
StringRef s = Saver.save(config->dynamicLinker);
StringRef s = saver.save(config->dynamicLinker);
ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1};
auto *sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents,
@ -2530,7 +2530,7 @@ createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> nameAttrs,
// speed it up.
size_t numShards = 32;
size_t concurrency = 1;
if (ThreadsEnabled)
if (threadsEnabled)
concurrency =
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards);
@ -2973,7 +2973,7 @@ void MergeNoTailSection::finalizeContents() {
// Concurrency level. Must be a power of 2 to avoid expensive modulo
// operations in the following tight loop.
size_t concurrency = 1;
if (ThreadsEnabled)
if (threadsEnabled)
concurrency =
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards);

View File

@ -350,7 +350,7 @@ void AArch64ABSLongThunk::writeTo(uint8_t *buf) {
}
void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__AArch64AbsLongThunk_" + destination.getName()),
addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
@ -376,7 +376,7 @@ void AArch64ADRPThunk::writeTo(uint8_t *buf) {
}
void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
}
@ -476,7 +476,7 @@ void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
}
void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
@ -494,7 +494,7 @@ void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
}
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
@ -515,7 +515,7 @@ void ARMV7PILongThunk::writeLong(uint8_t *buf) {
}
void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
@ -536,7 +536,7 @@ void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
}
void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__ThumbV7PILongThunk_" + destination.getName()),
addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
@ -551,7 +551,7 @@ void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
}
void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 4, isec);
@ -577,7 +577,7 @@ void ARMV5PILongThunk::writeLong(uint8_t *buf) {
}
void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
@ -607,7 +607,7 @@ void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
}
void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
@ -633,7 +633,7 @@ void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
}
void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
@ -651,7 +651,7 @@ void MipsThunk::writeTo(uint8_t *buf) {
}
void MipsThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
@ -675,7 +675,7 @@ void MicroMipsThunk::writeTo(uint8_t *buf) {
void MicroMipsThunk::addSymbols(ThunkSection &isec) {
Defined *d = addSymbol(
Saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
@ -699,7 +699,7 @@ void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
Defined *d = addSymbol(
Saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
@ -754,7 +754,7 @@ void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
else
os << ".plt_pic32.";
os << destination.getName();
addSymbol(Saver.save(os.str()), STT_FUNC, 0, isec);
addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
}
bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
@ -780,7 +780,7 @@ void PPC64PltCallStub::writeTo(uint8_t *buf) {
}
void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
Defined *s = addSymbol(Saver.save("__plt_" + destination.getName()), STT_FUNC,
Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
0, isec);
s->needsTocRestore = true;
}
@ -791,7 +791,7 @@ void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
}
void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
addSymbol(Saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
isec);
}

View File

@ -42,7 +42,7 @@ namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
Writer() : buffer(errorHandler().OutputBuffer) {}
Writer() : buffer(errorHandler().outputBuffer) {}
using Elf_Shdr = typename ELFT::Shdr;
using Elf_Ehdr = typename ELFT::Ehdr;
using Elf_Phdr = typename ELFT::Phdr;
@ -103,8 +103,8 @@ StringRef elf::getOutputSectionName(const InputSectionBase *s) {
if (InputSectionBase *rel = isec->getRelocatedSection()) {
OutputSection *out = rel->getOutputSection();
if (s->type == SHT_RELA)
return Saver.save(".rela" + out->name);
return Saver.save(".rel" + out->name);
return saver.save(".rela" + out->name);
return saver.save(".rel" + out->name);
}
}
@ -2006,8 +2006,8 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *sec) {
StringRef s = sec->name;
if (!isValidCIdentifier(s))
return;
addOptionalRegular(Saver.save("__start_" + s), sec, 0, STV_PROTECTED);
addOptionalRegular(Saver.save("__stop_" + s), sec, -1, STV_PROTECTED);
addOptionalRegular(saver.save("__start_" + s), sec, 0, STV_PROTECTED);
addOptionalRegular(saver.save("__stop_" + s), sec, -1, STV_PROTECTED);
}
static bool needsPtLoad(OutputSection *sec) {

View File

@ -65,7 +65,7 @@ enum {
#undef PREFIX
// Create table mapping all options defined in Options.td
static const opt::OptTable::Info InfoTable[] = {
static const opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
{X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
@ -76,14 +76,14 @@ static const opt::OptTable::Info InfoTable[] = {
namespace {
class MinGWOptTable : public opt::OptTable {
public:
MinGWOptTable() : OptTable(InfoTable, false) {}
opt::InputArgList parse(ArrayRef<const char *> Argv);
MinGWOptTable() : OptTable(infoTable, false) {}
opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace
static void printHelp(const char *Argv0) {
static void printHelp(const char *argv0) {
MinGWOptTable().PrintHelp(
outs(), (std::string(Argv0) + " [options] file...").c_str(), "lld",
outs(), (std::string(argv0) + " [options] file...").c_str(), "lld",
false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
}
@ -94,58 +94,58 @@ static cl::TokenizerCallback getQuotingStyle() {
return cl::TokenizeGNUCommandLine;
}
opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) {
unsigned MissingIndex;
unsigned MissingCount;
opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> argv) {
unsigned missingIndex;
unsigned missingCount;
SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
cl::ExpandResponseFiles(Saver, getQuotingStyle(), Vec);
opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
cl::ExpandResponseFiles(saver, getQuotingStyle(), vec);
opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
if (MissingCount)
fatal(StringRef(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
fatal("unknown argument: " + Arg->getAsString(Args));
return Args;
if (missingCount)
fatal(StringRef(args.getArgString(missingIndex)) + ": missing argument");
for (auto *arg : args.filtered(OPT_UNKNOWN))
fatal("unknown argument: " + arg->getAsString(args));
return args;
}
// Find a file by concatenating given paths.
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
SmallString<128> S;
sys::path::append(S, Path1, Path2);
if (sys::fs::exists(S))
return S.str().str();
static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
SmallString<128> s;
sys::path::append(s, path1, path2);
if (sys::fs::exists(s))
return s.str().str();
return None;
}
// This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths.
static std::string
searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) {
if (Name.startswith(":")) {
for (StringRef Dir : SearchPaths)
if (Optional<std::string> S = findFile(Dir, Name.substr(1)))
return *S;
fatal("unable to find library -l" + Name);
searchLibrary(StringRef name, ArrayRef<StringRef> searchPaths, bool bStatic) {
if (name.startswith(":")) {
for (StringRef dir : searchPaths)
if (Optional<std::string> s = findFile(dir, name.substr(1)))
return *s;
fatal("unable to find library -l" + name);
}
for (StringRef Dir : SearchPaths) {
if (!BStatic)
if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a"))
return *S;
if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
return *S;
for (StringRef dir : searchPaths) {
if (!bStatic)
if (Optional<std::string> s = findFile(dir, "lib" + name + ".dll.a"))
return *s;
if (Optional<std::string> s = findFile(dir, "lib" + name + ".a"))
return *s;
}
fatal("unable to find library -l" + Name);
fatal("unable to find library -l" + name);
}
// Convert Unix-ish command line arguments to Windows-ish ones and
// then call coff::link.
bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
MinGWOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) {
MinGWOptTable parser;
opt::InputArgList args = parser.parse(argsArr.slice(1));
if (Args.hasArg(OPT_help)) {
printHelp(ArgsArr[0]);
if (args.hasArg(OPT_help)) {
printHelp(argsArr[0]);
return true;
}
@ -154,199 +154,199 @@ bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
// still the newest version in March 2017) or earlier to recognize LLD as
// a GNU compatible linker. As long as an output for the -v option
// contains "GNU" or "with BFD", they recognize us as GNU-compatible.
if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
if (args.hasArg(OPT_v) || args.hasArg(OPT_version))
message(getLLDVersion() + " (compatible with GNU linkers)");
// The behavior of -v or --version is a bit strange, but this is
// needed for compatibility with GNU linkers.
if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l))
if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l))
return true;
if (Args.hasArg(OPT_version))
if (args.hasArg(OPT_version))
return true;
if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l))
if (!args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l))
fatal("no input files");
std::vector<std::string> LinkArgs;
auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); };
std::vector<std::string> linkArgs;
auto add = [&](const Twine &s) { linkArgs.push_back(s.str()); };
Add("lld-link");
Add("-lldmingw");
add("lld-link");
add("-lldmingw");
if (auto *A = Args.getLastArg(OPT_entry)) {
StringRef S = A->getValue();
if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_"))
Add("-entry:" + S.substr(1));
if (auto *a = args.getLastArg(OPT_entry)) {
StringRef s = a->getValue();
if (args.getLastArgValue(OPT_m) == "i386pe" && s.startswith("_"))
add("-entry:" + s.substr(1));
else
Add("-entry:" + S);
add("-entry:" + s);
}
if (Args.hasArg(OPT_major_os_version, OPT_minor_os_version,
if (args.hasArg(OPT_major_os_version, OPT_minor_os_version,
OPT_major_subsystem_version, OPT_minor_subsystem_version)) {
auto *MajOSVer = Args.getLastArg(OPT_major_os_version);
auto *MinOSVer = Args.getLastArg(OPT_minor_os_version);
auto *MajSubSysVer = Args.getLastArg(OPT_major_subsystem_version);
auto *MinSubSysVer = Args.getLastArg(OPT_minor_subsystem_version);
if (MajOSVer && MajSubSysVer &&
StringRef(MajOSVer->getValue()) != StringRef(MajSubSysVer->getValue()))
auto *majOSVer = args.getLastArg(OPT_major_os_version);
auto *minOSVer = args.getLastArg(OPT_minor_os_version);
auto *majSubSysVer = args.getLastArg(OPT_major_subsystem_version);
auto *minSubSysVer = args.getLastArg(OPT_minor_subsystem_version);
if (majOSVer && majSubSysVer &&
StringRef(majOSVer->getValue()) != StringRef(majSubSysVer->getValue()))
warn("--major-os-version and --major-subsystem-version set to differing "
"versions, not supported");
if (MinOSVer && MinSubSysVer &&
StringRef(MinOSVer->getValue()) != StringRef(MinSubSysVer->getValue()))
if (minOSVer && minSubSysVer &&
StringRef(minOSVer->getValue()) != StringRef(minSubSysVer->getValue()))
warn("--minor-os-version and --minor-subsystem-version set to differing "
"versions, not supported");
StringRef SubSys = Args.getLastArgValue(OPT_subs, "default");
StringRef Major = MajOSVer ? MajOSVer->getValue()
: MajSubSysVer ? MajSubSysVer->getValue() : "6";
StringRef Minor = MinOSVer ? MinOSVer->getValue()
: MinSubSysVer ? MinSubSysVer->getValue() : "";
StringRef Sep = Minor.empty() ? "" : ".";
Add("-subsystem:" + SubSys + "," + Major + Sep + Minor);
} else if (auto *A = Args.getLastArg(OPT_subs)) {
Add("-subsystem:" + StringRef(A->getValue()));
StringRef subSys = args.getLastArgValue(OPT_subs, "default");
StringRef major = majOSVer ? majOSVer->getValue()
: majSubSysVer ? majSubSysVer->getValue() : "6";
StringRef minor = minOSVer ? minOSVer->getValue()
: minSubSysVer ? minSubSysVer->getValue() : "";
StringRef sep = minor.empty() ? "" : ".";
add("-subsystem:" + subSys + "," + major + sep + minor);
} else if (auto *a = args.getLastArg(OPT_subs)) {
add("-subsystem:" + StringRef(a->getValue()));
}
if (auto *A = Args.getLastArg(OPT_out_implib))
Add("-implib:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_stack))
Add("-stack:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_output_def))
Add("-output-def:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_image_base))
Add("-base:" + StringRef(A->getValue()));
if (auto *A = Args.getLastArg(OPT_map))
Add("-lldmap:" + StringRef(A->getValue()));
if (auto *a = args.getLastArg(OPT_out_implib))
add("-implib:" + StringRef(a->getValue()));
if (auto *a = args.getLastArg(OPT_stack))
add("-stack:" + StringRef(a->getValue()));
if (auto *a = args.getLastArg(OPT_output_def))
add("-output-def:" + StringRef(a->getValue()));
if (auto *a = args.getLastArg(OPT_image_base))
add("-base:" + StringRef(a->getValue()));
if (auto *a = args.getLastArg(OPT_map))
add("-lldmap:" + StringRef(a->getValue()));
if (auto *A = Args.getLastArg(OPT_o))
Add("-out:" + StringRef(A->getValue()));
else if (Args.hasArg(OPT_shared))
Add("-out:a.dll");
if (auto *a = args.getLastArg(OPT_o))
add("-out:" + StringRef(a->getValue()));
else if (args.hasArg(OPT_shared))
add("-out:a.dll");
else
Add("-out:a.exe");
add("-out:a.exe");
if (auto *A = Args.getLastArg(OPT_pdb)) {
Add("-debug");
StringRef V = A->getValue();
if (!V.empty())
Add("-pdb:" + V);
} else if (Args.hasArg(OPT_strip_debug)) {
Add("-debug:symtab");
} else if (!Args.hasArg(OPT_strip_all)) {
Add("-debug:dwarf");
if (auto *a = args.getLastArg(OPT_pdb)) {
add("-debug");
StringRef v = a->getValue();
if (!v.empty())
add("-pdb:" + v);
} else if (args.hasArg(OPT_strip_debug)) {
add("-debug:symtab");
} else if (!args.hasArg(OPT_strip_all)) {
add("-debug:dwarf");
}
if (Args.hasArg(OPT_shared))
Add("-dll");
if (Args.hasArg(OPT_verbose))
Add("-verbose");
if (Args.hasArg(OPT_exclude_all_symbols))
Add("-exclude-all-symbols");
if (Args.hasArg(OPT_export_all_symbols))
Add("-export-all-symbols");
if (Args.hasArg(OPT_large_address_aware))
Add("-largeaddressaware");
if (Args.hasArg(OPT_kill_at))
Add("-kill-at");
if (Args.hasArg(OPT_appcontainer))
Add("-appcontainer");
if (args.hasArg(OPT_shared))
add("-dll");
if (args.hasArg(OPT_verbose))
add("-verbose");
if (args.hasArg(OPT_exclude_all_symbols))
add("-exclude-all-symbols");
if (args.hasArg(OPT_export_all_symbols))
add("-export-all-symbols");
if (args.hasArg(OPT_large_address_aware))
add("-largeaddressaware");
if (args.hasArg(OPT_kill_at))
add("-kill-at");
if (args.hasArg(OPT_appcontainer))
add("-appcontainer");
if (Args.getLastArgValue(OPT_m) != "thumb2pe" &&
Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase))
Add("-dynamicbase:no");
if (args.getLastArgValue(OPT_m) != "thumb2pe" &&
args.getLastArgValue(OPT_m) != "arm64pe" && !args.hasArg(OPT_dynamicbase))
add("-dynamicbase:no");
if (Args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false))
Add("-timestamp:0");
if (args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false))
add("-timestamp:0");
if (Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false))
Add("-opt:ref");
if (args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false))
add("-opt:ref");
else
Add("-opt:noref");
add("-opt:noref");
if (auto *A = Args.getLastArg(OPT_icf)) {
StringRef S = A->getValue();
if (S == "all")
Add("-opt:icf");
else if (S == "safe" || S == "none")
Add("-opt:noicf");
if (auto *a = args.getLastArg(OPT_icf)) {
StringRef s = a->getValue();
if (s == "all")
add("-opt:icf");
else if (s == "safe" || s == "none")
add("-opt:noicf");
else
fatal("unknown parameter: --icf=" + S);
fatal("unknown parameter: --icf=" + s);
} else {
Add("-opt:noicf");
add("-opt:noicf");
}
if (auto *A = Args.getLastArg(OPT_m)) {
StringRef S = A->getValue();
if (S == "i386pe")
Add("-machine:x86");
else if (S == "i386pep")
Add("-machine:x64");
else if (S == "thumb2pe")
Add("-machine:arm");
else if (S == "arm64pe")
Add("-machine:arm64");
if (auto *a = args.getLastArg(OPT_m)) {
StringRef s = a->getValue();
if (s == "i386pe")
add("-machine:x86");
else if (s == "i386pep")
add("-machine:x64");
else if (s == "thumb2pe")
add("-machine:arm");
else if (s == "arm64pe")
add("-machine:arm64");
else
fatal("unknown parameter: -m" + S);
fatal("unknown parameter: -m" + s);
}
for (auto *A : Args.filtered(OPT_mllvm))
Add("-mllvm:" + StringRef(A->getValue()));
for (auto *a : args.filtered(OPT_mllvm))
add("-mllvm:" + StringRef(a->getValue()));
for (auto *A : Args.filtered(OPT_Xlink))
Add(A->getValue());
for (auto *a : args.filtered(OPT_Xlink))
add(a->getValue());
if (Args.getLastArgValue(OPT_m) == "i386pe")
Add("-alternatename:__image_base__=___ImageBase");
if (args.getLastArgValue(OPT_m) == "i386pe")
add("-alternatename:__image_base__=___ImageBase");
else
Add("-alternatename:__image_base__=__ImageBase");
add("-alternatename:__image_base__=__ImageBase");
for (auto *A : Args.filtered(OPT_require_defined))
Add("-include:" + StringRef(A->getValue()));
for (auto *A : Args.filtered(OPT_undefined))
Add("-includeoptional:" + StringRef(A->getValue()));
for (auto *a : args.filtered(OPT_require_defined))
add("-include:" + StringRef(a->getValue()));
for (auto *a : args.filtered(OPT_undefined))
add("-includeoptional:" + StringRef(a->getValue()));
std::vector<StringRef> SearchPaths;
for (auto *A : Args.filtered(OPT_L)) {
SearchPaths.push_back(A->getValue());
Add("-libpath:" + StringRef(A->getValue()));
std::vector<StringRef> searchPaths;
for (auto *a : args.filtered(OPT_L)) {
searchPaths.push_back(a->getValue());
add("-libpath:" + StringRef(a->getValue()));
}
StringRef Prefix = "";
bool Static = false;
for (auto *A : Args) {
switch (A->getOption().getID()) {
StringRef prefix = "";
bool isStatic = false;
for (auto *a : args) {
switch (a->getOption().getID()) {
case OPT_INPUT:
if (StringRef(A->getValue()).endswith_lower(".def"))
Add("-def:" + StringRef(A->getValue()));
if (StringRef(a->getValue()).endswith_lower(".def"))
add("-def:" + StringRef(a->getValue()));
else
Add(Prefix + StringRef(A->getValue()));
add(prefix + StringRef(a->getValue()));
break;
case OPT_l:
Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static));
add(prefix + searchLibrary(a->getValue(), searchPaths, isStatic));
break;
case OPT_whole_archive:
Prefix = "-wholearchive:";
prefix = "-wholearchive:";
break;
case OPT_no_whole_archive:
Prefix = "";
prefix = "";
break;
case OPT_Bstatic:
Static = true;
isStatic = true;
break;
case OPT_Bdynamic:
Static = false;
isStatic = false;
break;
}
}
if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH))
outs() << llvm::join(LinkArgs, " ") << "\n";
if (args.hasArg(OPT_verbose) || args.hasArg(OPT__HASH_HASH_HASH))
outs() << llvm::join(linkArgs, " ") << "\n";
if (Args.hasArg(OPT__HASH_HASH_HASH))
if (args.hasArg(OPT__HASH_HASH_HASH))
return true;
// Repack vector of strings to vector of const char pointers for coff::link.
std::vector<const char *> Vec;
for (const std::string &S : LinkArgs)
Vec.push_back(S.c_str());
return coff::link(Vec, true);
std::vector<const char *> vec;
for (const std::string &s : linkArgs)
vec.push_back(s.c_str());
return coff::link(vec, true);
}

View File

@ -23,19 +23,19 @@ class InputArgList;
namespace lld {
namespace args {
llvm::CodeGenOpt::Level getCGOptLevel(int OptLevelLTO);
llvm::CodeGenOpt::Level getCGOptLevel(int optLevelLTO);
int64_t getInteger(llvm::opt::InputArgList &Args, unsigned Key,
int64_t getInteger(llvm::opt::InputArgList &args, unsigned key,
int64_t Default);
std::vector<StringRef> getStrings(llvm::opt::InputArgList &Args, int Id);
std::vector<StringRef> getStrings(llvm::opt::InputArgList &args, int id);
uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key,
uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key,
uint64_t Default);
std::vector<StringRef> getLines(MemoryBufferRef MB);
std::vector<StringRef> getLines(MemoryBufferRef mb);
StringRef getFilenameWithoutExe(StringRef Path);
StringRef getFilenameWithoutExe(StringRef path);
} // namespace args
} // namespace lld

View File

@ -14,28 +14,28 @@
namespace lld {
namespace coff {
bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &diag = llvm::errs());
}
namespace mingw {
bool link(llvm::ArrayRef<const char *> Args,
llvm::raw_ostream &Diag = llvm::errs());
bool link(llvm::ArrayRef<const char *> args,
llvm::raw_ostream &diag = llvm::errs());
}
namespace elf {
bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &diag = llvm::errs());
}
namespace mach_o {
bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &diag = llvm::errs());
}
namespace wasm {
bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &diag = llvm::errs());
}
}

View File

@ -82,74 +82,74 @@ namespace lld {
class ErrorHandler {
public:
uint64_t ErrorCount = 0;
uint64_t ErrorLimit = 20;
StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now";
StringRef LogName = "lld";
llvm::raw_ostream *ErrorOS = &llvm::errs();
bool ColorDiagnostics = llvm::errs().has_colors();
bool ExitEarly = true;
bool FatalWarnings = false;
bool Verbose = false;
uint64_t errorCount = 0;
uint64_t errorLimit = 20;
StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
StringRef logName = "lld";
llvm::raw_ostream *errorOS = &llvm::errs();
bool colorDiagnostics = llvm::errs().has_colors();
bool exitEarly = true;
bool fatalWarnings = false;
bool verbose = false;
void error(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
void log(const Twine &Msg);
void message(const Twine &Msg);
void warn(const Twine &Msg);
void error(const Twine &msg);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg);
void log(const Twine &msg);
void message(const Twine &msg);
void warn(const Twine &msg);
std::unique_ptr<llvm::FileOutputBuffer> OutputBuffer;
std::unique_ptr<llvm::FileOutputBuffer> outputBuffer;
private:
void print(StringRef S, raw_ostream::Colors C);
void print(StringRef s, raw_ostream::Colors c);
};
/// Returns the default error handler.
ErrorHandler &errorHandler();
inline void error(const Twine &Msg) { errorHandler().error(Msg); }
inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) {
errorHandler().fatal(Msg);
inline void error(const Twine &msg) { errorHandler().error(msg); }
inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg) {
errorHandler().fatal(msg);
}
inline void log(const Twine &Msg) { errorHandler().log(Msg); }
inline void message(const Twine &Msg) { errorHandler().message(Msg); }
inline void warn(const Twine &Msg) { errorHandler().warn(Msg); }
inline uint64_t errorCount() { return errorHandler().ErrorCount; }
inline void log(const Twine &msg) { errorHandler().log(msg); }
inline void message(const Twine &msg) { errorHandler().message(msg); }
inline void warn(const Twine &msg) { errorHandler().warn(msg); }
inline uint64_t errorCount() { return errorHandler().errorCount; }
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
LLVM_ATTRIBUTE_NORETURN void exitLld(int val);
void diagnosticHandler(const llvm::DiagnosticInfo &DI);
void checkError(Error E);
void diagnosticHandler(const llvm::DiagnosticInfo &di);
void checkError(Error e);
// check functions are convenient functions to strip errors
// from error-or-value objects.
template <class T> T check(ErrorOr<T> E) {
if (auto EC = E.getError())
fatal(EC.message());
return std::move(*E);
template <class T> T check(ErrorOr<T> e) {
if (auto ec = e.getError())
fatal(ec.message());
return std::move(*e);
}
template <class T> T check(Expected<T> E) {
if (!E)
fatal(llvm::toString(E.takeError()));
return std::move(*E);
template <class T> T check(Expected<T> e) {
if (!e)
fatal(llvm::toString(e.takeError()));
return std::move(*e);
}
template <class T>
T check2(ErrorOr<T> E, llvm::function_ref<std::string()> Prefix) {
if (auto EC = E.getError())
fatal(Prefix() + ": " + EC.message());
return std::move(*E);
T check2(ErrorOr<T> e, llvm::function_ref<std::string()> prefix) {
if (auto ec = e.getError())
fatal(prefix() + ": " + ec.message());
return std::move(*e);
}
template <class T>
T check2(Expected<T> E, llvm::function_ref<std::string()> Prefix) {
if (!E)
fatal(Prefix() + ": " + toString(E.takeError()));
return std::move(*E);
T check2(Expected<T> e, llvm::function_ref<std::string()> prefix) {
if (!e)
fatal(prefix() + ": " + toString(e.takeError()));
return std::move(*e);
}
inline std::string toString(const Twine &S) { return S.str(); }
inline std::string toString(const Twine &s) { return s.str(); }
// To evaluate the second argument lazily, we use C macro.
#define CHECK(E, S) check2((E), [&] { return toString(S); })

View File

@ -13,8 +13,8 @@
#include <system_error>
namespace lld {
void unlinkAsync(StringRef Path);
std::error_code tryCreateFile(StringRef Path);
void unlinkAsync(StringRef path);
std::error_code tryCreateFile(StringRef path);
} // namespace lld
#endif

View File

@ -28,30 +28,30 @@
namespace lld {
// Use this arena if your object doesn't have a destructor.
extern llvm::BumpPtrAllocator BAlloc;
extern llvm::StringSaver Saver;
extern llvm::BumpPtrAllocator bAlloc;
extern llvm::StringSaver saver;
void freeArena();
// These two classes are hack to keep track of all
// SpecificBumpPtrAllocator instances.
struct SpecificAllocBase {
SpecificAllocBase() { Instances.push_back(this); }
SpecificAllocBase() { instances.push_back(this); }
virtual ~SpecificAllocBase() = default;
virtual void reset() = 0;
static std::vector<SpecificAllocBase *> Instances;
static std::vector<SpecificAllocBase *> instances;
};
template <class T> struct SpecificAlloc : public SpecificAllocBase {
void reset() override { Alloc.DestroyAll(); }
llvm::SpecificBumpPtrAllocator<T> Alloc;
void reset() override { alloc.DestroyAll(); }
llvm::SpecificBumpPtrAllocator<T> alloc;
};
// Use this arena if your object has a destructor.
// Your destructor will be invoked from freeArena().
template <typename T, typename... U> T *make(U &&... Args) {
static SpecificAlloc<T> Alloc;
return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
template <typename T, typename... U> T *make(U &&... args) {
static SpecificAlloc<T> alloc;
return new (alloc.alloc.Allocate()) T(std::forward<U>(args)...);
}
} // namespace lld

View File

@ -22,13 +22,13 @@ namespace lld {
// Makes a given pathname an absolute path first, and then remove
// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
// assuming that the current directory is "/home/john/bar".
std::string relativeToRoot(StringRef Path);
std::string relativeToRoot(StringRef path);
// Quote a given string if it contains a space character.
std::string quote(StringRef S);
std::string quote(StringRef s);
// Returns the string form of the given argument.
std::string toString(const llvm::opt::Arg &Arg);
std::string toString(const llvm::opt::Arg &arg);
}
#endif

View File

@ -19,25 +19,25 @@
namespace lld {
// Returns a demangled C++ symbol name. If Name is not a mangled
// name, it returns Optional::None.
llvm::Optional<std::string> demangleItanium(llvm::StringRef Name);
llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
llvm::Optional<std::string> demangleItanium(llvm::StringRef name);
llvm::Optional<std::string> demangleMSVC(llvm::StringRef s);
std::vector<uint8_t> parseHex(llvm::StringRef S);
bool isValidCIdentifier(llvm::StringRef S);
std::vector<uint8_t> parseHex(llvm::StringRef s);
bool isValidCIdentifier(llvm::StringRef s);
// Write the contents of the a buffer to a file
void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path);
void saveBuffer(llvm::StringRef buffer, const llvm::Twine &path);
// This class represents multiple glob patterns.
class StringMatcher {
public:
StringMatcher() = default;
explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat);
explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> pat);
bool match(llvm::StringRef S) const;
bool match(llvm::StringRef s) const;
private:
std::vector<llvm::GlobPattern> Patterns;
std::vector<llvm::GlobPattern> patterns;
};
} // namespace lld

View File

@ -63,28 +63,28 @@
namespace lld {
extern bool ThreadsEnabled;
extern bool threadsEnabled;
template <typename R, class FuncTy> void parallelForEach(R &&Range, FuncTy Fn) {
if (ThreadsEnabled)
for_each(llvm::parallel::par, std::begin(Range), std::end(Range), Fn);
template <typename R, class FuncTy> void parallelForEach(R &&range, FuncTy fn) {
if (threadsEnabled)
for_each(llvm::parallel::par, std::begin(range), std::end(range), fn);
else
for_each(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn);
for_each(llvm::parallel::seq, std::begin(range), std::end(range), fn);
}
inline void parallelForEachN(size_t Begin, size_t End,
llvm::function_ref<void(size_t)> Fn) {
if (ThreadsEnabled)
for_each_n(llvm::parallel::par, Begin, End, Fn);
inline void parallelForEachN(size_t begin, size_t end,
llvm::function_ref<void(size_t)> fn) {
if (threadsEnabled)
for_each_n(llvm::parallel::par, begin, end, fn);
else
for_each_n(llvm::parallel::seq, Begin, End, Fn);
for_each_n(llvm::parallel::seq, begin, end, fn);
}
template <typename R, class FuncTy> void parallelSort(R &&Range, FuncTy Fn) {
if (ThreadsEnabled)
sort(llvm::parallel::par, std::begin(Range), std::end(Range), Fn);
template <typename R, class FuncTy> void parallelSort(R &&range, FuncTy fn) {
if (threadsEnabled)
sort(llvm::parallel::par, std::begin(range), std::end(range), fn);
else
sort(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn);
sort(llvm::parallel::seq, std::begin(range), std::end(range), fn);
}
} // namespace lld

View File

@ -21,18 +21,18 @@ namespace lld {
class Timer;
struct ScopedTimer {
explicit ScopedTimer(Timer &T);
explicit ScopedTimer(Timer &t);
~ScopedTimer();
void stop();
Timer *T = nullptr;
Timer *t = nullptr;
};
class Timer {
public:
Timer(llvm::StringRef Name, Timer &Parent);
Timer(llvm::StringRef name, Timer &parent);
static Timer &root();
@ -43,14 +43,14 @@ public:
double millis() const;
private:
explicit Timer(llvm::StringRef Name);
void print(int Depth, double TotalDuration, bool Recurse = true) const;
explicit Timer(llvm::StringRef name);
void print(int depth, double totalDuration, bool recurse = true) const;
std::chrono::time_point<std::chrono::high_resolution_clock> StartTime;
std::chrono::nanoseconds Total;
std::vector<Timer *> Children;
std::string Name;
Timer *Parent;
std::chrono::time_point<std::chrono::high_resolution_clock> startTime;
std::chrono::nanoseconds total;
std::vector<Timer *> children;
std::string name;
Timer *parent;
};
} // namespace lld

View File

@ -333,8 +333,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) {
Twine(unknownArg->getAsString(parsedArgs)));
}
errorHandler().Verbose = parsedArgs.hasArg(OPT_v);
errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
errorHandler().verbose = parsedArgs.hasArg(OPT_v);
errorHandler().errorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
@ -637,7 +637,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) {
// Now that we've constructed the final set of search paths, print out those
// search paths in verbose mode.
if (errorHandler().Verbose) {
if (errorHandler().verbose) {
message("Library search paths:");
for (auto path : ctx.searchDirs()) {
message(" " + path);
@ -1145,13 +1145,13 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
/// This is where the link is actually performed.
bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
raw_ostream &Error) {
errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
errorHandler().ErrorLimitExceededMsg =
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"'-error-limit 0' to see all errors)";
errorHandler().ErrorOS = &Error;
errorHandler().ExitEarly = CanExitEarly;
errorHandler().ColorDiagnostics = Error.has_colors();
errorHandler().errorOS = &Error;
errorHandler().exitEarly = CanExitEarly;
errorHandler().colorDiagnostics = Error.has_colors();
MachOLinkingContext ctx;
if (!parse(args, ctx))
@ -1196,9 +1196,9 @@ bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
if (auto ec = pm.runOnFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
*errorHandler().ErrorOS << "Failed to run passes on file '"
*errorHandler().errorOS << "Failed to run passes on file '"
<< ctx.outputPath() << "': ";
logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS,
std::string());
return false;
}
@ -1210,9 +1210,9 @@ bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
if (auto ec = ctx.writeFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
*errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath()
*errorHandler().errorOS << "Failed to write file '" << ctx.outputPath()
<< "': ";
logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS,
std::string());
return false;
}

View File

@ -49,13 +49,13 @@ enum Flavor {
Wasm, // -flavor wasm
};
LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
errs() << S << "\n";
LLVM_ATTRIBUTE_NORETURN static void die(const Twine &s) {
errs() << s << "\n";
exit(1);
}
static Flavor getFlavor(StringRef S) {
return StringSwitch<Flavor>(S)
static Flavor getFlavor(StringRef s) {
return StringSwitch<Flavor>(s)
.CasesLower("ld", "ld.lld", "gnu", Gnu)
.CasesLower("wasm", "ld-wasm", Wasm)
.CaseLower("link", WinLink)
@ -69,29 +69,29 @@ static cl::TokenizerCallback getDefaultQuotingStyle() {
return cl::TokenizeGNUCommandLine;
}
static bool isPETargetName(StringRef S) {
return S == "i386pe" || S == "i386pep" || S == "thumb2pe" || S == "arm64pe";
static bool isPETargetName(StringRef s) {
return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe";
}
static bool isPETarget(std::vector<const char *> &V) {
for (auto It = V.begin(); It + 1 != V.end(); ++It) {
if (StringRef(*It) != "-m")
static bool isPETarget(std::vector<const char *> &v) {
for (auto it = v.begin(); it + 1 != v.end(); ++it) {
if (StringRef(*it) != "-m")
continue;
return isPETargetName(*(It + 1));
return isPETargetName(*(it + 1));
}
// Expand response files (arguments in the form of @<filename>)
// to allow detecting the -m argument from arguments in them.
SmallVector<const char *, 256> ExpandedArgs(V.data(), V.data() + V.size());
cl::ExpandResponseFiles(Saver, getDefaultQuotingStyle(), ExpandedArgs);
for (auto It = ExpandedArgs.begin(); It + 1 != ExpandedArgs.end(); ++It) {
if (StringRef(*It) != "-m")
SmallVector<const char *, 256> expandedArgs(v.data(), v.data() + v.size());
cl::ExpandResponseFiles(saver, getDefaultQuotingStyle(), expandedArgs);
for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {
if (StringRef(*it) != "-m")
continue;
return isPETargetName(*(It + 1));
return isPETargetName(*(it + 1));
}
return false;
}
static Flavor parseProgname(StringRef Progname) {
static Flavor parseProgname(StringRef progname) {
#if __APPLE__
// Use Darwin driver for "ld" on Darwin.
if (Progname == "ld")
@ -100,36 +100,36 @@ static Flavor parseProgname(StringRef Progname) {
#if LLVM_ON_UNIX
// Use GNU driver for "ld" on other Unix-like system.
if (Progname == "ld")
if (progname == "ld")
return Gnu;
#endif
// Progname may be something like "lld-gnu". Parse it.
SmallVector<StringRef, 3> V;
Progname.split(V, "-");
for (StringRef S : V)
if (Flavor F = getFlavor(S))
return F;
SmallVector<StringRef, 3> v;
progname.split(v, "-");
for (StringRef s : v)
if (Flavor f = getFlavor(s))
return f;
return Invalid;
}
static Flavor parseFlavor(std::vector<const char *> &V) {
static Flavor parseFlavor(std::vector<const char *> &v) {
// Parse -flavor option.
if (V.size() > 1 && V[1] == StringRef("-flavor")) {
if (V.size() <= 2)
if (v.size() > 1 && v[1] == StringRef("-flavor")) {
if (v.size() <= 2)
die("missing arg value for '-flavor'");
Flavor F = getFlavor(V[2]);
if (F == Invalid)
die("Unknown flavor: " + StringRef(V[2]));
V.erase(V.begin() + 1, V.begin() + 3);
return F;
Flavor f = getFlavor(v[2]);
if (f == Invalid)
die("Unknown flavor: " + StringRef(v[2]));
v.erase(v.begin() + 1, v.begin() + 3);
return f;
}
// Deduct the flavor from argv[0].
StringRef Arg0 = path::filename(V[0]);
if (Arg0.endswith_lower(".exe"))
Arg0 = Arg0.drop_back(4);
return parseProgname(Arg0);
StringRef arg0 = path::filename(v[0]);
if (arg0.endswith_lower(".exe"))
arg0 = arg0.drop_back(4);
return parseProgname(arg0);
}
// If this function returns true, lld calls _exit() so that it quickly
@ -142,21 +142,21 @@ static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; }
/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
int main(int Argc, const char **Argv) {
InitLLVM X(Argc, Argv);
int main(int argc, const char **argv) {
InitLLVM x(argc, argv);
std::vector<const char *> Args(Argv, Argv + Argc);
switch (parseFlavor(Args)) {
std::vector<const char *> args(argv, argv + argc);
switch (parseFlavor(args)) {
case Gnu:
if (isPETarget(Args))
return !mingw::link(Args);
return !elf::link(Args, canExitEarly());
if (isPETarget(args))
return !mingw::link(args);
return !elf::link(args, canExitEarly());
case WinLink:
return !coff::link(Args, canExitEarly());
return !coff::link(args, canExitEarly());
case Darwin:
return !mach_o::link(Args, canExitEarly());
return !mach_o::link(args, canExitEarly());
case Wasm:
return !wasm::link(Args, canExitEarly());
return !wasm::link(args, canExitEarly());
default:
die("lld is a generic driver.\n"
"Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"

View File

@ -22,58 +22,58 @@ namespace wasm {
// and such fields have the same name as the corresponding options.
// Most fields are initialized by the driver.
struct Configuration {
bool AllowUndefined;
bool CheckFeatures;
bool CompressRelocations;
bool Demangle;
bool DisableVerify;
bool EmitRelocs;
bool ExportAll;
bool ExportDynamic;
bool ExportTable;
bool GcSections;
bool ImportMemory;
bool SharedMemory;
bool PassiveSegments;
bool ImportTable;
bool MergeDataSegments;
bool Pie;
bool PrintGcSections;
bool Relocatable;
bool SaveTemps;
bool Shared;
bool StripAll;
bool StripDebug;
bool StackFirst;
bool Trace;
uint32_t GlobalBase;
uint32_t InitialMemory;
uint32_t MaxMemory;
uint32_t ZStackSize;
unsigned LTOPartitions;
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
bool allowUndefined;
bool checkFeatures;
bool compressRelocations;
bool demangle;
bool disableVerify;
bool emitRelocs;
bool exportAll;
bool exportDynamic;
bool exportTable;
bool gcSections;
bool importMemory;
bool sharedMemory;
bool passiveSegments;
bool importTable;
bool mergeDataSegments;
bool pie;
bool printGcSections;
bool relocatable;
bool saveTemps;
bool shared;
bool stripAll;
bool stripDebug;
bool stackFirst;
bool trace;
uint32_t globalBase;
uint32_t initialMemory;
uint32_t maxMemory;
uint32_t zStackSize;
unsigned ltoPartitions;
unsigned ltoo;
unsigned optimize;
unsigned thinLTOJobs;
llvm::StringRef Entry;
llvm::StringRef OutputFile;
llvm::StringRef ThinLTOCacheDir;
llvm::StringRef entry;
llvm::StringRef outputFile;
llvm::StringRef thinLTOCacheDir;
llvm::StringSet<> AllowUndefinedSymbols;
llvm::StringSet<> ExportedSymbols;
std::vector<llvm::StringRef> SearchPaths;
llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::Optional<std::vector<std::string>> Features;
llvm::StringSet<> allowUndefinedSymbols;
llvm::StringSet<> exportedSymbols;
std::vector<llvm::StringRef> searchPaths;
llvm::CachePruningPolicy thinLTOCachePolicy;
llvm::Optional<std::vector<std::string>> features;
// The following config options do not directly correspond to any
// particualr command line options.
// True if we are creating position-independent code.
bool Pic;
bool isPic;
};
// The only instance of Configuration struct.
extern Configuration *Config;
extern Configuration *config;
} // namespace wasm
} // namespace lld

File diff suppressed because it is too large Load Diff

View File

@ -22,8 +22,8 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::wasm;
StringRef lld::relocTypeToString(uint8_t RelocType) {
switch (RelocType) {
StringRef lld::relocTypeToString(uint8_t relocType) {
switch (relocType) {
#define WASM_RELOC(NAME, REL) \
case REL: \
return #NAME;
@ -33,67 +33,67 @@ StringRef lld::relocTypeToString(uint8_t RelocType) {
llvm_unreachable("unknown reloc type");
}
std::string lld::toString(const InputChunk *C) {
return (toString(C->File) + ":(" + C->getName() + ")").str();
std::string lld::toString(const InputChunk *c) {
return (toString(c->file) + ":(" + c->getName() + ")").str();
}
StringRef InputChunk::getComdatName() const {
uint32_t Index = getComdat();
if (Index == UINT32_MAX)
uint32_t index = getComdat();
if (index == UINT32_MAX)
return StringRef();
return File->getWasmObj()->linkingData().Comdats[Index];
return file->getWasmObj()->linkingData().Comdats[index];
}
void InputChunk::verifyRelocTargets() const {
for (const WasmRelocation &Rel : Relocations) {
uint32_t ExistingValue;
unsigned BytesRead = 0;
uint32_t Offset = Rel.Offset - getInputSectionOffset();
const uint8_t *Loc = data().data() + Offset;
switch (Rel.Type) {
for (const WasmRelocation &rel : relocations) {
uint32_t existingValue;
unsigned bytesRead = 0;
uint32_t offset = rel.Offset - getInputSectionOffset();
const uint8_t *loc = data().data() + offset;
switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
ExistingValue = decodeULEB128(Loc, &BytesRead);
existingValue = decodeULEB128(loc, &bytesRead);
break;
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead));
existingValue = static_cast<uint32_t>(decodeSLEB128(loc, &bytesRead));
break;
case R_WASM_TABLE_INDEX_I32:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_FUNCTION_OFFSET_I32:
case R_WASM_SECTION_OFFSET_I32:
ExistingValue = static_cast<uint32_t>(read32le(Loc));
existingValue = static_cast<uint32_t>(read32le(loc));
break;
default:
llvm_unreachable("unknown relocation type");
}
if (BytesRead && BytesRead != 5)
if (bytesRead && bytesRead != 5)
warn("expected LEB at relocation site be 5-byte padded");
if (Rel.Type != R_WASM_GLOBAL_INDEX_LEB) {
uint32_t ExpectedValue = File->calcExpectedValue(Rel);
if (ExpectedValue != ExistingValue)
warn("unexpected existing value for " + relocTypeToString(Rel.Type) +
": existing=" + Twine(ExistingValue) +
" expected=" + Twine(ExpectedValue));
if (rel.Type != R_WASM_GLOBAL_INDEX_LEB) {
uint32_t expectedValue = file->calcExpectedValue(rel);
if (expectedValue != existingValue)
warn("unexpected existing value for " + relocTypeToString(rel.Type) +
": existing=" + Twine(existingValue) +
" expected=" + Twine(expectedValue));
}
}
}
// Copy this input chunk to an mmap'ed output file and apply relocations.
void InputChunk::writeTo(uint8_t *Buf) const {
void InputChunk::writeTo(uint8_t *buf) const {
// Copy contents
memcpy(Buf + OutputOffset, data().data(), data().size());
memcpy(buf + outputOffset, data().data(), data().size());
// Apply relocations
if (Relocations.empty())
if (relocations.empty())
return;
#ifndef NDEBUG
@ -101,38 +101,38 @@ void InputChunk::writeTo(uint8_t *Buf) const {
#endif
LLVM_DEBUG(dbgs() << "applying relocations: " << getName()
<< " count=" << Relocations.size() << "\n");
int32_t Off = OutputOffset - getInputSectionOffset();
<< " count=" << relocations.size() << "\n");
int32_t off = outputOffset - getInputSectionOffset();
for (const WasmRelocation &Rel : Relocations) {
uint8_t *Loc = Buf + Rel.Offset + Off;
uint32_t Value = File->calcNewValue(Rel);
LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(Rel.Type));
if (Rel.Type != R_WASM_TYPE_INDEX_LEB)
LLVM_DEBUG(dbgs() << " sym=" << File->getSymbols()[Rel.Index]->getName());
LLVM_DEBUG(dbgs() << " addend=" << Rel.Addend << " index=" << Rel.Index
<< " value=" << Value << " offset=" << Rel.Offset
for (const WasmRelocation &rel : relocations) {
uint8_t *loc = buf + rel.Offset + off;
uint32_t value = file->calcNewValue(rel);
LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type));
if (rel.Type != R_WASM_TYPE_INDEX_LEB)
LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
LLVM_DEBUG(dbgs() << " addend=" << rel.Addend << " index=" << rel.Index
<< " value=" << value << " offset=" << rel.Offset
<< "\n");
switch (Rel.Type) {
switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
encodeULEB128(Value, Loc, 5);
encodeULEB128(value, loc, 5);
break;
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
encodeSLEB128(static_cast<int32_t>(value), loc, 5);
break;
case R_WASM_TABLE_INDEX_I32:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_FUNCTION_OFFSET_I32:
case R_WASM_SECTION_OFFSET_I32:
write32le(Loc, Value);
write32le(loc, value);
break;
default:
llvm_unreachable("unknown relocation type");
@ -143,59 +143,59 @@ void InputChunk::writeTo(uint8_t *Buf) const {
// Copy relocation entries to a given output stream.
// This function is used only when a user passes "-r". For a regular link,
// we consume relocations instead of copying them to an output file.
void InputChunk::writeRelocations(raw_ostream &OS) const {
if (Relocations.empty())
void InputChunk::writeRelocations(raw_ostream &os) const {
if (relocations.empty())
return;
int32_t Off = OutputOffset - getInputSectionOffset();
LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName()
<< " offset=" << Twine(Off) << "\n");
int32_t off = outputOffset - getInputSectionOffset();
LLVM_DEBUG(dbgs() << "writeRelocations: " << file->getName()
<< " offset=" << Twine(off) << "\n");
for (const WasmRelocation &Rel : Relocations) {
writeUleb128(OS, Rel.Type, "reloc type");
writeUleb128(OS, Rel.Offset + Off, "reloc offset");
writeUleb128(OS, File->calcNewIndex(Rel), "reloc index");
for (const WasmRelocation &rel : relocations) {
writeUleb128(os, rel.Type, "reloc type");
writeUleb128(os, rel.Offset + off, "reloc offset");
writeUleb128(os, file->calcNewIndex(rel), "reloc index");
if (relocTypeHasAddend(Rel.Type))
writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend");
if (relocTypeHasAddend(rel.Type))
writeSleb128(os, file->calcNewAddend(rel), "reloc addend");
}
}
void InputFunction::setFunctionIndex(uint32_t Index) {
void InputFunction::setFunctionIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName()
<< " -> " << Index << "\n");
<< " -> " << index << "\n");
assert(!hasFunctionIndex());
FunctionIndex = Index;
functionIndex = index;
}
void InputFunction::setTableIndex(uint32_t Index) {
void InputFunction::setTableIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "
<< Index << "\n");
<< index << "\n");
assert(!hasTableIndex());
TableIndex = Index;
tableIndex = index;
}
// Write a relocation value without padding and return the number of bytes
// witten.
static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
uint32_t Value) {
switch (Rel.Type) {
static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel,
uint32_t value) {
switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
return encodeULEB128(Value, Buf);
return encodeULEB128(value, buf);
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
return encodeSLEB128(static_cast<int32_t>(Value), Buf);
return encodeSLEB128(static_cast<int32_t>(value), buf);
default:
llvm_unreachable("unexpected relocation type");
}
}
static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
switch (Rel.Type) {
static unsigned getRelocWidthPadded(const WasmRelocation &rel) {
switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
@ -209,9 +209,9 @@ static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
}
}
static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
uint8_t Buf[5];
return writeCompressedReloc(Buf, Rel, Value);
static unsigned getRelocWidth(const WasmRelocation &rel, uint32_t value) {
uint8_t buf[5];
return writeCompressedReloc(buf, rel, value);
}
// Relocations of type LEB and SLEB in the code section are padded to 5 bytes
@ -225,124 +225,124 @@ static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
// This function only computes the final output size. It must be called
// before getSize() is used to calculate of layout of the code section.
void InputFunction::calculateSize() {
if (!File || !Config->CompressRelocations)
if (!file || !config->compressRelocations)
return;
LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n");
const uint8_t *SecStart = File->CodeSection->Content.data();
const uint8_t *FuncStart = SecStart + getInputSectionOffset();
uint32_t FunctionSizeLength;
decodeULEB128(FuncStart, &FunctionSizeLength);
const uint8_t *secStart = file->codeSection->Content.data();
const uint8_t *funcStart = secStart + getInputSectionOffset();
uint32_t functionSizeLength;
decodeULEB128(funcStart, &functionSizeLength);
uint32_t Start = getInputSectionOffset();
uint32_t End = Start + Function->Size;
uint32_t start = getInputSectionOffset();
uint32_t end = start + function->Size;
uint32_t LastRelocEnd = Start + FunctionSizeLength;
for (const WasmRelocation &Rel : Relocations) {
LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n");
CompressedFuncSize += Rel.Offset - LastRelocEnd;
CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel));
LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel);
uint32_t lastRelocEnd = start + functionSizeLength;
for (const WasmRelocation &rel : relocations) {
LLVM_DEBUG(dbgs() << " region: " << (rel.Offset - lastRelocEnd) << "\n");
compressedFuncSize += rel.Offset - lastRelocEnd;
compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel));
lastRelocEnd = rel.Offset + getRelocWidthPadded(rel);
}
LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n");
CompressedFuncSize += End - LastRelocEnd;
LLVM_DEBUG(dbgs() << " final region: " << (end - lastRelocEnd) << "\n");
compressedFuncSize += end - lastRelocEnd;
// Now we know how long the resulting function is we can add the encoding
// of its length
uint8_t Buf[5];
CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf);
uint8_t buf[5];
compressedSize = compressedFuncSize + encodeULEB128(compressedFuncSize, buf);
LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n");
LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n");
LLVM_DEBUG(dbgs() << " calculateSize orig: " << function->Size << "\n");
LLVM_DEBUG(dbgs() << " calculateSize new: " << compressedSize << "\n");
}
// Override the default writeTo method so that we can (optionally) write the
// compressed version of the function.
void InputFunction::writeTo(uint8_t *Buf) const {
if (!File || !Config->CompressRelocations)
return InputChunk::writeTo(Buf);
void InputFunction::writeTo(uint8_t *buf) const {
if (!file || !config->compressRelocations)
return InputChunk::writeTo(buf);
Buf += OutputOffset;
uint8_t *Orig = Buf;
(void)Orig;
buf += outputOffset;
uint8_t *orig = buf;
(void)orig;
const uint8_t *SecStart = File->CodeSection->Content.data();
const uint8_t *FuncStart = SecStart + getInputSectionOffset();
const uint8_t *End = FuncStart + Function->Size;
uint32_t Count;
decodeULEB128(FuncStart, &Count);
FuncStart += Count;
const uint8_t *secStart = file->codeSection->Content.data();
const uint8_t *funcStart = secStart + getInputSectionOffset();
const uint8_t *end = funcStart + function->Size;
uint32_t count;
decodeULEB128(funcStart, &count);
funcStart += count;
LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n");
Buf += encodeULEB128(CompressedFuncSize, Buf);
const uint8_t *LastRelocEnd = FuncStart;
for (const WasmRelocation &Rel : Relocations) {
unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd;
LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n");
memcpy(Buf, LastRelocEnd, ChunkSize);
Buf += ChunkSize;
Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel));
LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel);
buf += encodeULEB128(compressedFuncSize, buf);
const uint8_t *lastRelocEnd = funcStart;
for (const WasmRelocation &rel : relocations) {
unsigned chunkSize = (secStart + rel.Offset) - lastRelocEnd;
LLVM_DEBUG(dbgs() << " write chunk: " << chunkSize << "\n");
memcpy(buf, lastRelocEnd, chunkSize);
buf += chunkSize;
buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel));
lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel);
}
unsigned ChunkSize = End - LastRelocEnd;
LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n");
memcpy(Buf, LastRelocEnd, ChunkSize);
LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n");
unsigned chunkSize = end - lastRelocEnd;
LLVM_DEBUG(dbgs() << " write final chunk: " << chunkSize << "\n");
memcpy(buf, lastRelocEnd, chunkSize);
LLVM_DEBUG(dbgs() << " total: " << (buf + chunkSize - orig) << "\n");
}
// Generate code to apply relocations to the data section at runtime.
// This is only called when generating shared libaries (PIC) where address are
// not known at static link time.
void InputSegment::generateRelocationCode(raw_ostream &OS) const {
void InputSegment::generateRelocationCode(raw_ostream &os) const {
LLVM_DEBUG(dbgs() << "generating runtime relocations: " << getName()
<< " count=" << Relocations.size() << "\n");
<< " count=" << relocations.size() << "\n");
// TODO(sbc): Encode the relocations in the data section and write a loop
// here to apply them.
uint32_t SegmentVA = OutputSeg->StartVA + OutputSegmentOffset;
for (const WasmRelocation &Rel : Relocations) {
uint32_t Offset = Rel.Offset - getInputSectionOffset();
uint32_t OutputOffset = SegmentVA + Offset;
uint32_t segmentVA = outputSeg->startVA + outputSegmentOffset;
for (const WasmRelocation &rel : relocations) {
uint32_t offset = rel.Offset - getInputSectionOffset();
uint32_t outputOffset = segmentVA + offset;
LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(Rel.Type)
<< " addend=" << Rel.Addend << " index=" << Rel.Index
<< " output offset=" << OutputOffset << "\n");
LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type)
<< " addend=" << rel.Addend << " index=" << rel.Index
<< " output offset=" << outputOffset << "\n");
// Get __memory_base
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(OS, WasmSym::MemoryBase->getGlobalIndex(), "memory_base");
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
// Add the offset of the relocation
writeU8(OS, WASM_OPCODE_I32_CONST, "I32_CONST");
writeSleb128(OS, OutputOffset, "offset");
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
writeU8(os, WASM_OPCODE_I32_CONST, "I32_CONST");
writeSleb128(os, outputOffset, "offset");
writeU8(os, WASM_OPCODE_I32_ADD, "ADD");
Symbol *Sym = File->getSymbol(Rel);
Symbol *sym = file->getSymbol(rel);
// Now figure out what we want to store
if (Sym->hasGOTIndex()) {
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(OS, Sym->getGOTIndex(), "global index");
if (Rel.Addend) {
writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
writeSleb128(OS, Rel.Addend, "addend");
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
if (sym->hasGOTIndex()) {
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, sym->getGOTIndex(), "global index");
if (rel.Addend) {
writeU8(os, WASM_OPCODE_I32_CONST, "CONST");
writeSleb128(os, rel.Addend, "addend");
writeU8(os, WASM_OPCODE_I32_ADD, "ADD");
}
} else {
const GlobalSymbol* BaseSymbol = WasmSym::MemoryBase;
if (Rel.Type == R_WASM_TABLE_INDEX_I32)
BaseSymbol = WasmSym::TableBase;
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(OS, BaseSymbol->getGlobalIndex(), "base");
writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
writeSleb128(OS, File->calcNewValue(Rel), "offset");
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
if (rel.Type == R_WASM_TABLE_INDEX_I32)
baseSymbol = WasmSym::tableBase;
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
writeU8(os, WASM_OPCODE_I32_CONST, "CONST");
writeSleb128(os, file->calcNewValue(rel), "offset");
writeU8(os, WASM_OPCODE_I32_ADD, "ADD");
}
// Store that value at the virtual address
writeU8(OS, WASM_OPCODE_I32_STORE, "I32_STORE");
writeUleb128(OS, 2, "align");
writeUleb128(OS, 0, "offset");
writeU8(os, WASM_OPCODE_I32_STORE, "I32_STORE");
writeUleb128(os, 2, "align");
writeUleb128(os, 0, "offset");
}
}

View File

@ -37,15 +37,15 @@ class InputChunk {
public:
enum Kind { DataSegment, Function, SyntheticFunction, Section };
Kind kind() const { return SectionKind; }
Kind kind() const { return sectionKind; }
virtual uint32_t getSize() const { return data().size(); }
virtual uint32_t getInputSize() const { return getSize(); };
virtual void writeTo(uint8_t *SectionStart) const;
virtual void writeTo(uint8_t *sectionStart) const;
ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
void setRelocations(ArrayRef<WasmRelocation> Rs) { Relocations = Rs; }
ArrayRef<WasmRelocation> getRelocations() const { return relocations; }
void setRelocations(ArrayRef<WasmRelocation> rs) { relocations = rs; }
virtual StringRef getName() const = 0;
virtual StringRef getDebugName() const = 0;
@ -53,23 +53,23 @@ public:
StringRef getComdatName() const;
virtual uint32_t getInputSectionOffset() const = 0;
size_t getNumRelocations() const { return Relocations.size(); }
void writeRelocations(llvm::raw_ostream &OS) const;
size_t getNumRelocations() const { return relocations.size(); }
void writeRelocations(llvm::raw_ostream &os) const;
ObjFile *File;
int32_t OutputOffset = 0;
ObjFile *file;
int32_t outputOffset = 0;
// Signals that the section is part of the output. The garbage collector,
// and COMDAT handling can set a sections' Live bit.
// If GC is disabled, all sections start out as live by default.
unsigned Live : 1;
unsigned live : 1;
// Signals the chunk was discarded by COMDAT handling.
unsigned Discarded : 1;
unsigned discarded : 1;
protected:
InputChunk(ObjFile *F, Kind K)
: File(F), Live(!Config->GcSections), Discarded(false), SectionKind(K) {}
InputChunk(ObjFile *f, Kind k)
: file(f), live(!config->gcSections), discarded(false), sectionKind(k) {}
virtual ~InputChunk() = default;
virtual ArrayRef<uint8_t> data() const = 0;
@ -77,8 +77,8 @@ protected:
// This is performed only debug builds as an extra sanity check.
void verifyRelocTargets() const;
ArrayRef<WasmRelocation> Relocations;
Kind SectionKind;
ArrayRef<WasmRelocation> relocations;
Kind sectionKind;
};
// Represents a WebAssembly data segment which can be included as part of
@ -91,65 +91,65 @@ protected:
// each global variable.
class InputSegment : public InputChunk {
public:
InputSegment(const WasmSegment &Seg, ObjFile *F)
: InputChunk(F, InputChunk::DataSegment), Segment(Seg) {}
InputSegment(const WasmSegment &seg, ObjFile *f)
: InputChunk(f, InputChunk::DataSegment), segment(seg) {}
static bool classof(const InputChunk *C) { return C->kind() == DataSegment; }
static bool classof(const InputChunk *c) { return c->kind() == DataSegment; }
void generateRelocationCode(raw_ostream &OS) const;
void generateRelocationCode(raw_ostream &os) const;
uint32_t getAlignment() const { return Segment.Data.Alignment; }
StringRef getName() const override { return Segment.Data.Name; }
uint32_t getAlignment() const { return segment.Data.Alignment; }
StringRef getName() const override { return segment.Data.Name; }
StringRef getDebugName() const override { return StringRef(); }
uint32_t getComdat() const override { return Segment.Data.Comdat; }
uint32_t getComdat() const override { return segment.Data.Comdat; }
uint32_t getInputSectionOffset() const override {
return Segment.SectionOffset;
return segment.SectionOffset;
}
const OutputSegment *OutputSeg = nullptr;
int32_t OutputSegmentOffset = 0;
const OutputSegment *outputSeg = nullptr;
int32_t outputSegmentOffset = 0;
protected:
ArrayRef<uint8_t> data() const override { return Segment.Data.Content; }
ArrayRef<uint8_t> data() const override { return segment.Data.Content; }
const WasmSegment &Segment;
const WasmSegment &segment;
};
// Represents a single wasm function within and input file. These are
// combined to create the final output CODE section.
class InputFunction : public InputChunk {
public:
InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F)
: InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {}
InputFunction(const WasmSignature &s, const WasmFunction *func, ObjFile *f)
: InputChunk(f, InputChunk::Function), signature(s), function(func) {}
static bool classof(const InputChunk *C) {
return C->kind() == InputChunk::Function ||
C->kind() == InputChunk::SyntheticFunction;
static bool classof(const InputChunk *c) {
return c->kind() == InputChunk::Function ||
c->kind() == InputChunk::SyntheticFunction;
}
void writeTo(uint8_t *SectionStart) const override;
StringRef getName() const override { return Function->SymbolName; }
StringRef getDebugName() const override { return Function->DebugName; }
uint32_t getComdat() const override { return Function->Comdat; }
void writeTo(uint8_t *sectionStart) const override;
StringRef getName() const override { return function->SymbolName; }
StringRef getDebugName() const override { return function->DebugName; }
uint32_t getComdat() const override { return function->Comdat; }
uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; }
uint32_t getFunctionCodeOffset() const { return function->CodeOffset; }
uint32_t getSize() const override {
if (Config->CompressRelocations && File) {
assert(CompressedSize);
return CompressedSize;
if (config->compressRelocations && file) {
assert(compressedSize);
return compressedSize;
}
return data().size();
}
uint32_t getInputSize() const override { return Function->Size; }
uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
void setFunctionIndex(uint32_t Index);
uint32_t getInputSize() const override { return function->Size; }
uint32_t getFunctionIndex() const { return functionIndex.getValue(); }
bool hasFunctionIndex() const { return functionIndex.hasValue(); }
void setFunctionIndex(uint32_t index);
uint32_t getInputSectionOffset() const override {
return Function->CodeSectionOffset;
return function->CodeSectionOffset;
}
uint32_t getTableIndex() const { return TableIndex.getValue(); }
bool hasTableIndex() const { return TableIndex.hasValue(); }
void setTableIndex(uint32_t Index);
uint32_t getTableIndex() const { return tableIndex.getValue(); }
bool hasTableIndex() const { return tableIndex.hasValue(); }
void setTableIndex(uint32_t index);
// The size of a given input function can depend on the values of the
// LEB relocations within it. This finalizeContents method is called after
@ -157,76 +157,76 @@ public:
// called.
void calculateSize();
const WasmSignature &Signature;
const WasmSignature &signature;
protected:
ArrayRef<uint8_t> data() const override {
assert(!Config->CompressRelocations);
return File->CodeSection->Content.slice(getInputSectionOffset(),
Function->Size);
assert(!config->compressRelocations);
return file->codeSection->Content.slice(getInputSectionOffset(),
function->Size);
}
const WasmFunction *Function;
llvm::Optional<uint32_t> FunctionIndex;
llvm::Optional<uint32_t> TableIndex;
uint32_t CompressedFuncSize = 0;
uint32_t CompressedSize = 0;
const WasmFunction *function;
llvm::Optional<uint32_t> functionIndex;
llvm::Optional<uint32_t> tableIndex;
uint32_t compressedFuncSize = 0;
uint32_t compressedSize = 0;
};
class SyntheticFunction : public InputFunction {
public:
SyntheticFunction(const WasmSignature &S, StringRef Name,
StringRef DebugName = {})
: InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) {
SectionKind = InputChunk::SyntheticFunction;
SyntheticFunction(const WasmSignature &s, StringRef name,
StringRef debugName = {})
: InputFunction(s, nullptr, nullptr), name(name), debugName(debugName) {
sectionKind = InputChunk::SyntheticFunction;
}
static bool classof(const InputChunk *C) {
return C->kind() == InputChunk::SyntheticFunction;
static bool classof(const InputChunk *c) {
return c->kind() == InputChunk::SyntheticFunction;
}
StringRef getName() const override { return Name; }
StringRef getDebugName() const override { return DebugName; }
StringRef getName() const override { return name; }
StringRef getDebugName() const override { return debugName; }
uint32_t getComdat() const override { return UINT32_MAX; }
void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; }
void setBody(ArrayRef<uint8_t> body_) { body = body_; }
protected:
ArrayRef<uint8_t> data() const override { return Body; }
ArrayRef<uint8_t> data() const override { return body; }
StringRef Name;
StringRef DebugName;
ArrayRef<uint8_t> Body;
StringRef name;
StringRef debugName;
ArrayRef<uint8_t> body;
};
// Represents a single Wasm Section within an input file.
class InputSection : public InputChunk {
public:
InputSection(const WasmSection &S, ObjFile *F)
: InputChunk(F, InputChunk::Section), Section(S) {
assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM);
InputSection(const WasmSection &s, ObjFile *f)
: InputChunk(f, InputChunk::Section), section(s) {
assert(section.Type == llvm::wasm::WASM_SEC_CUSTOM);
}
StringRef getName() const override { return Section.Name; }
StringRef getName() const override { return section.Name; }
StringRef getDebugName() const override { return StringRef(); }
uint32_t getComdat() const override { return UINT32_MAX; }
OutputSection *OutputSec = nullptr;
OutputSection *outputSec = nullptr;
protected:
ArrayRef<uint8_t> data() const override { return Section.Content; }
ArrayRef<uint8_t> data() const override { return section.Content; }
// Offset within the input section. This is only zero since this chunk
// type represents an entire input section, not part of one.
uint32_t getInputSectionOffset() const override { return 0; }
const WasmSection &Section;
const WasmSection &section;
};
} // namespace wasm
std::string toString(const wasm::InputChunk *);
StringRef relocTypeToString(uint8_t RelocType);
StringRef relocTypeToString(uint8_t relocType);
} // namespace lld

View File

@ -28,33 +28,33 @@ namespace wasm {
// form the final EVENTS section.
class InputEvent {
public:
InputEvent(const WasmSignature &S, const WasmEvent &E, ObjFile *F)
: File(F), Event(E), Signature(S), Live(!Config->GcSections) {}
InputEvent(const WasmSignature &s, const WasmEvent &e, ObjFile *f)
: file(f), event(e), signature(s), live(!config->gcSections) {}
StringRef getName() const { return Event.SymbolName; }
const WasmEventType &getType() const { return Event.Type; }
StringRef getName() const { return event.SymbolName; }
const WasmEventType &getType() const { return event.Type; }
uint32_t getEventIndex() const { return EventIndex.getValue(); }
bool hasEventIndex() const { return EventIndex.hasValue(); }
void setEventIndex(uint32_t Index) {
uint32_t getEventIndex() const { return eventIndex.getValue(); }
bool hasEventIndex() const { return eventIndex.hasValue(); }
void setEventIndex(uint32_t index) {
assert(!hasEventIndex());
EventIndex = Index;
eventIndex = index;
}
ObjFile *File;
WasmEvent Event;
const WasmSignature &Signature;
ObjFile *file;
WasmEvent event;
const WasmSignature &signature;
bool Live = false;
bool live = false;
protected:
llvm::Optional<uint32_t> EventIndex;
llvm::Optional<uint32_t> eventIndex;
};
} // namespace wasm
inline std::string toString(const wasm::InputEvent *E) {
return (toString(E->File) + ":(" + E->getName() + ")").str();
inline std::string toString(const wasm::InputEvent *e) {
return (toString(e->file) + ":(" + e->getName() + ")").str();
}
} // namespace lld

View File

@ -29,77 +29,77 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::wasm;
std::unique_ptr<llvm::TarWriter> lld::wasm::Tar;
std::unique_ptr<llvm::TarWriter> lld::wasm::tar;
Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
log("Loading: " + Path);
Optional<MemoryBufferRef> lld::wasm::readFile(StringRef path) {
log("Loading: " + path);
auto MBOrErr = MemoryBuffer::getFile(Path);
if (auto EC = MBOrErr.getError()) {
error("cannot open " + Path + ": " + EC.message());
auto mbOrErr = MemoryBuffer::getFile(path);
if (auto ec = mbOrErr.getError()) {
error("cannot open " + path + ": " + ec.message());
return None;
}
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
std::unique_ptr<MemoryBuffer> &mb = *mbOrErr;
MemoryBufferRef mbref = mb->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take MB ownership
if (Tar)
Tar->append(relativeToRoot(Path), MBRef.getBuffer());
return MBRef;
if (tar)
tar->append(relativeToRoot(path), mbref.getBuffer());
return mbref;
}
InputFile *lld::wasm::createObjectFile(MemoryBufferRef MB,
StringRef ArchiveName) {
file_magic Magic = identify_magic(MB.getBuffer());
if (Magic == file_magic::wasm_object) {
std::unique_ptr<Binary> Bin =
CHECK(createBinary(MB), MB.getBufferIdentifier());
auto *Obj = cast<WasmObjectFile>(Bin.get());
if (Obj->isSharedObject())
return make<SharedFile>(MB);
return make<ObjFile>(MB, ArchiveName);
InputFile *lld::wasm::createObjectFile(MemoryBufferRef mb,
StringRef archiveName) {
file_magic magic = identify_magic(mb.getBuffer());
if (magic == file_magic::wasm_object) {
std::unique_ptr<Binary> bin =
CHECK(createBinary(mb), mb.getBufferIdentifier());
auto *obj = cast<WasmObjectFile>(bin.get());
if (obj->isSharedObject())
return make<SharedFile>(mb);
return make<ObjFile>(mb, archiveName);
}
if (Magic == file_magic::bitcode)
return make<BitcodeFile>(MB, ArchiveName);
if (magic == file_magic::bitcode)
return make<BitcodeFile>(mb, archiveName);
fatal("unknown file type: " + MB.getBufferIdentifier());
fatal("unknown file type: " + mb.getBufferIdentifier());
}
void ObjFile::dumpInfo() const {
log("info for: " + toString(this) +
"\n Symbols : " + Twine(Symbols.size()) +
"\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) +
"\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals()) +
"\n Event Imports : " + Twine(WasmObj->getNumImportedEvents()));
"\n Symbols : " + Twine(symbols.size()) +
"\n Function Imports : " + Twine(wasmObj->getNumImportedFunctions()) +
"\n Global Imports : " + Twine(wasmObj->getNumImportedGlobals()) +
"\n Event Imports : " + Twine(wasmObj->getNumImportedEvents()));
}
// Relocations contain either symbol or type indices. This function takes a
// relocation and returns relocated index (i.e. translates from the input
// symbol/type space to the output symbol/type space).
uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) {
assert(TypeIsUsed[Reloc.Index]);
return TypeMap[Reloc.Index];
uint32_t ObjFile::calcNewIndex(const WasmRelocation &reloc) const {
if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
assert(typeIsUsed[reloc.Index]);
return typeMap[reloc.Index];
}
const Symbol *Sym = Symbols[Reloc.Index];
if (auto *SS = dyn_cast<SectionSymbol>(Sym))
Sym = SS->getOutputSectionSymbol();
return Sym->getOutputSymbolIndex();
const Symbol *sym = symbols[reloc.Index];
if (auto *ss = dyn_cast<SectionSymbol>(sym))
sym = ss->getOutputSectionSymbol();
return sym->getOutputSymbolIndex();
}
// Relocations can contain addend for combined sections. This function takes a
// relocation and returns updated addend by offset in the output section.
uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const {
switch (Reloc.Type) {
uint32_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
switch (reloc.Type) {
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_FUNCTION_OFFSET_I32:
return Reloc.Addend;
return reloc.Addend;
case R_WASM_SECTION_OFFSET_I32:
return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend;
default:
llvm_unreachable("unexpected relocation type");
}
@ -108,42 +108,42 @@ uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const {
// Calculate the value we expect to find at the relocation location.
// This is used as a sanity check before applying a relocation to a given
// location. It is useful for catching bugs in the compiler and linker.
uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
switch (Reloc.Type) {
uint32_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB: {
const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
return TableEntries[Sym.Info.ElementIndex];
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
return tableEntries[sym.Info.ElementIndex];
}
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_REL_SLEB: {
const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
if (Sym.isUndefined())
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
if (sym.isUndefined())
return 0;
const WasmSegment &Segment =
WasmObj->dataSegments()[Sym.Info.DataRef.Segment];
return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset +
Reloc.Addend;
const WasmSegment &segment =
wasmObj->dataSegments()[sym.Info.DataRef.Segment];
return segment.Data.Offset.Value.Int32 + sym.Info.DataRef.Offset +
reloc.Addend;
}
case R_WASM_FUNCTION_OFFSET_I32: {
const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
InputFunction *F =
Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()];
return F->getFunctionInputOffset() + F->getFunctionCodeOffset() +
Reloc.Addend;
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
InputFunction *f =
functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()];
return f->getFunctionInputOffset() + f->getFunctionCodeOffset() +
reloc.Addend;
}
case R_WASM_SECTION_OFFSET_I32:
return Reloc.Addend;
return reloc.Addend;
case R_WASM_TYPE_INDEX_LEB:
return Reloc.Index;
return reloc.Index;
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB: {
const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
return Sym.Info.ElementIndex;
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
return sym.Info.ElementIndex;
}
default:
llvm_unreachable("unknown relocation type");
@ -151,115 +151,115 @@ uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
}
// Translate from the relocation's index into the final linked output value.
uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
const Symbol* Sym = nullptr;
if (Reloc.Type != R_WASM_TYPE_INDEX_LEB) {
Sym = Symbols[Reloc.Index];
uint32_t ObjFile::calcNewValue(const WasmRelocation &reloc) const {
const Symbol* sym = nullptr;
if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {
sym = symbols[reloc.Index];
// We can end up with relocations against non-live symbols. For example
// in debug sections.
if ((isa<FunctionSymbol>(Sym) || isa<DataSymbol>(Sym)) && !Sym->isLive())
if ((isa<FunctionSymbol>(sym) || isa<DataSymbol>(sym)) && !sym->isLive())
return 0;
}
switch (Reloc.Type) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
if (Config->Pic && !getFunctionSymbol(Reloc.Index)->hasTableIndex())
if (config->isPic && !getFunctionSymbol(reloc.Index)->hasTableIndex())
return 0;
return getFunctionSymbol(Reloc.Index)->getTableIndex();
return getFunctionSymbol(reloc.Index)->getTableIndex();
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
if (isa<UndefinedData>(Sym))
if (isa<UndefinedData>(sym))
return 0;
return cast<DefinedData>(Sym)->getVirtualAddress() + Reloc.Addend;
return cast<DefinedData>(sym)->getVirtualAddress() + reloc.Addend;
case R_WASM_TYPE_INDEX_LEB:
return TypeMap[Reloc.Index];
return typeMap[reloc.Index];
case R_WASM_FUNCTION_INDEX_LEB:
return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
return getFunctionSymbol(reloc.Index)->getFunctionIndex();
case R_WASM_GLOBAL_INDEX_LEB:
if (auto GS = dyn_cast<GlobalSymbol>(Sym))
return GS->getGlobalIndex();
return Sym->getGOTIndex();
if (auto gs = dyn_cast<GlobalSymbol>(sym))
return gs->getGlobalIndex();
return sym->getGOTIndex();
case R_WASM_EVENT_INDEX_LEB:
return getEventSymbol(Reloc.Index)->getEventIndex();
return getEventSymbol(reloc.Index)->getEventIndex();
case R_WASM_FUNCTION_OFFSET_I32: {
auto *F = cast<DefinedFunction>(Sym);
return F->Function->OutputOffset + F->Function->getFunctionCodeOffset() +
Reloc.Addend;
auto *f = cast<DefinedFunction>(sym);
return f->function->outputOffset + f->function->getFunctionCodeOffset() +
reloc.Addend;
}
case R_WASM_SECTION_OFFSET_I32:
return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend;
default:
llvm_unreachable("unknown relocation type");
}
}
template <class T>
static void setRelocs(const std::vector<T *> &Chunks,
const WasmSection *Section) {
if (!Section)
static void setRelocs(const std::vector<T *> &chunks,
const WasmSection *section) {
if (!section)
return;
ArrayRef<WasmRelocation> Relocs = Section->Relocations;
assert(std::is_sorted(Relocs.begin(), Relocs.end(),
[](const WasmRelocation &R1, const WasmRelocation &R2) {
return R1.Offset < R2.Offset;
ArrayRef<WasmRelocation> relocs = section->Relocations;
assert(std::is_sorted(relocs.begin(), relocs.end(),
[](const WasmRelocation &r1, const WasmRelocation &r2) {
return r1.Offset < r2.Offset;
}));
assert(std::is_sorted(
Chunks.begin(), Chunks.end(), [](InputChunk *C1, InputChunk *C2) {
return C1->getInputSectionOffset() < C2->getInputSectionOffset();
chunks.begin(), chunks.end(), [](InputChunk *c1, InputChunk *c2) {
return c1->getInputSectionOffset() < c2->getInputSectionOffset();
}));
auto RelocsNext = Relocs.begin();
auto RelocsEnd = Relocs.end();
auto RelocLess = [](const WasmRelocation &R, uint32_t Val) {
return R.Offset < Val;
auto relocsNext = relocs.begin();
auto relocsEnd = relocs.end();
auto relocLess = [](const WasmRelocation &r, uint32_t val) {
return r.Offset < val;
};
for (InputChunk *C : Chunks) {
auto RelocsStart = std::lower_bound(RelocsNext, RelocsEnd,
C->getInputSectionOffset(), RelocLess);
RelocsNext = std::lower_bound(
RelocsStart, RelocsEnd, C->getInputSectionOffset() + C->getInputSize(),
RelocLess);
C->setRelocations(ArrayRef<WasmRelocation>(RelocsStart, RelocsNext));
for (InputChunk *c : chunks) {
auto relocsStart = std::lower_bound(relocsNext, relocsEnd,
c->getInputSectionOffset(), relocLess);
relocsNext = std::lower_bound(
relocsStart, relocsEnd, c->getInputSectionOffset() + c->getInputSize(),
relocLess);
c->setRelocations(ArrayRef<WasmRelocation>(relocsStart, relocsNext));
}
}
void ObjFile::parse(bool IgnoreComdats) {
void ObjFile::parse(bool ignoreComdats) {
// Parse a memory buffer as a wasm file.
LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this));
std::unique_ptr<Binary> bin = CHECK(createBinary(mb), toString(this));
auto *Obj = dyn_cast<WasmObjectFile>(Bin.get());
if (!Obj)
auto *obj = dyn_cast<WasmObjectFile>(bin.get());
if (!obj)
fatal(toString(this) + ": not a wasm file");
if (!Obj->isRelocatableObject())
if (!obj->isRelocatableObject())
fatal(toString(this) + ": not a relocatable wasm file");
Bin.release();
WasmObj.reset(Obj);
bin.release();
wasmObj.reset(obj);
// Build up a map of function indices to table indices for use when
// verifying the existing table index relocations
uint32_t TotalFunctions =
WasmObj->getNumImportedFunctions() + WasmObj->functions().size();
TableEntries.resize(TotalFunctions);
for (const WasmElemSegment &Seg : WasmObj->elements()) {
if (Seg.Offset.Opcode != WASM_OPCODE_I32_CONST)
uint32_t totalFunctions =
wasmObj->getNumImportedFunctions() + wasmObj->functions().size();
tableEntries.resize(totalFunctions);
for (const WasmElemSegment &seg : wasmObj->elements()) {
if (seg.Offset.Opcode != WASM_OPCODE_I32_CONST)
fatal(toString(this) + ": invalid table elements");
uint32_t Offset = Seg.Offset.Value.Int32;
for (uint32_t Index = 0; Index < Seg.Functions.size(); Index++) {
uint32_t offset = seg.Offset.Value.Int32;
for (uint32_t index = 0; index < seg.Functions.size(); index++) {
uint32_t FunctionIndex = Seg.Functions[Index];
TableEntries[FunctionIndex] = Offset + Index;
uint32_t functionIndex = seg.Functions[index];
tableEntries[functionIndex] = offset + index;
}
}
uint32_t SectionIndex = 0;
uint32_t sectionIndex = 0;
// Bool for each symbol, true if called directly. This allows us to implement
// a weaker form of signature checking where undefined functions that are not
@ -267,185 +267,185 @@ void ObjFile::parse(bool IgnoreComdats) {
// function's signature. We cannot do this for directly called functions
// because those signatures are checked at validation times.
// See https://bugs.llvm.org/show_bug.cgi?id=40412
std::vector<bool> IsCalledDirectly(WasmObj->getNumberOfSymbols(), false);
for (const SectionRef &Sec : WasmObj->sections()) {
const WasmSection &Section = WasmObj->getWasmSection(Sec);
std::vector<bool> isCalledDirectly(wasmObj->getNumberOfSymbols(), false);
for (const SectionRef &sec : wasmObj->sections()) {
const WasmSection &section = wasmObj->getWasmSection(sec);
// Wasm objects can have at most one code and one data section.
if (Section.Type == WASM_SEC_CODE) {
assert(!CodeSection);
CodeSection = &Section;
} else if (Section.Type == WASM_SEC_DATA) {
assert(!DataSection);
DataSection = &Section;
} else if (Section.Type == WASM_SEC_CUSTOM) {
CustomSections.emplace_back(make<InputSection>(Section, this));
CustomSections.back()->setRelocations(Section.Relocations);
CustomSectionsByIndex[SectionIndex] = CustomSections.back();
if (section.Type == WASM_SEC_CODE) {
assert(!codeSection);
codeSection = &section;
} else if (section.Type == WASM_SEC_DATA) {
assert(!dataSection);
dataSection = &section;
} else if (section.Type == WASM_SEC_CUSTOM) {
customSections.emplace_back(make<InputSection>(section, this));
customSections.back()->setRelocations(section.Relocations);
customSectionsByIndex[sectionIndex] = customSections.back();
}
SectionIndex++;
sectionIndex++;
// Scans relocations to dermine determine if a function symbol is called
// directly
for (const WasmRelocation &Reloc : Section.Relocations)
if (Reloc.Type == R_WASM_FUNCTION_INDEX_LEB)
IsCalledDirectly[Reloc.Index] = true;
for (const WasmRelocation &reloc : section.Relocations)
if (reloc.Type == R_WASM_FUNCTION_INDEX_LEB)
isCalledDirectly[reloc.Index] = true;
}
TypeMap.resize(getWasmObj()->types().size());
TypeIsUsed.resize(getWasmObj()->types().size(), false);
typeMap.resize(getWasmObj()->types().size());
typeIsUsed.resize(getWasmObj()->types().size(), false);
ArrayRef<StringRef> Comdats = WasmObj->linkingData().Comdats;
for (StringRef Comdat : Comdats) {
bool IsNew = IgnoreComdats || Symtab->addComdat(Comdat);
KeptComdats.push_back(IsNew);
ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats;
for (StringRef comdat : comdats) {
bool isNew = ignoreComdats || symtab->addComdat(comdat);
keptComdats.push_back(isNew);
}
// Populate `Segments`.
for (const WasmSegment &S : WasmObj->dataSegments()) {
auto* Seg = make<InputSegment>(S, this);
Seg->Discarded = isExcludedByComdat(Seg);
Segments.emplace_back(Seg);
for (const WasmSegment &s : wasmObj->dataSegments()) {
auto* seg = make<InputSegment>(s, this);
seg->discarded = isExcludedByComdat(seg);
segments.emplace_back(seg);
}
setRelocs(Segments, DataSection);
setRelocs(segments, dataSection);
// Populate `Functions`.
ArrayRef<WasmFunction> Funcs = WasmObj->functions();
ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
ArrayRef<WasmSignature> Types = WasmObj->types();
Functions.reserve(Funcs.size());
ArrayRef<WasmFunction> funcs = wasmObj->functions();
ArrayRef<uint32_t> funcTypes = wasmObj->functionTypes();
ArrayRef<WasmSignature> types = wasmObj->types();
functions.reserve(funcs.size());
for (size_t I = 0, E = Funcs.size(); I != E; ++I) {
auto* Func = make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this);
Func->Discarded = isExcludedByComdat(Func);
Functions.emplace_back(Func);
for (size_t i = 0, e = funcs.size(); i != e; ++i) {
auto* func = make<InputFunction>(types[funcTypes[i]], &funcs[i], this);
func->discarded = isExcludedByComdat(func);
functions.emplace_back(func);
}
setRelocs(Functions, CodeSection);
setRelocs(functions, codeSection);
// Populate `Globals`.
for (const WasmGlobal &G : WasmObj->globals())
Globals.emplace_back(make<InputGlobal>(G, this));
for (const WasmGlobal &g : wasmObj->globals())
globals.emplace_back(make<InputGlobal>(g, this));
// Populate `Events`.
for (const WasmEvent &E : WasmObj->events())
Events.emplace_back(make<InputEvent>(Types[E.Type.SigIndex], E, this));
for (const WasmEvent &e : wasmObj->events())
events.emplace_back(make<InputEvent>(types[e.Type.SigIndex], e, this));
// Populate `Symbols` based on the WasmSymbols in the object.
Symbols.reserve(WasmObj->getNumberOfSymbols());
for (const SymbolRef &Sym : WasmObj->symbols()) {
const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
if (WasmSym.isDefined()) {
symbols.reserve(wasmObj->getNumberOfSymbols());
for (const SymbolRef &sym : wasmObj->symbols()) {
const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl());
if (wasmSym.isDefined()) {
// createDefined may fail if the symbol is comdat excluded in which case
// we fall back to creating an undefined symbol
if (Symbol *D = createDefined(WasmSym)) {
Symbols.push_back(D);
if (Symbol *d = createDefined(wasmSym)) {
symbols.push_back(d);
continue;
}
}
size_t Idx = Symbols.size();
Symbols.push_back(createUndefined(WasmSym, IsCalledDirectly[Idx]));
size_t idx = symbols.size();
symbols.push_back(createUndefined(wasmSym, isCalledDirectly[idx]));
}
}
bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
uint32_t C = Chunk->getComdat();
if (C == UINT32_MAX)
bool ObjFile::isExcludedByComdat(InputChunk *chunk) const {
uint32_t c = chunk->getComdat();
if (c == UINT32_MAX)
return false;
return !KeptComdats[C];
return !keptComdats[c];
}
FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const {
return cast<FunctionSymbol>(Symbols[Index]);
FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t index) const {
return cast<FunctionSymbol>(symbols[index]);
}
GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
return cast<GlobalSymbol>(Symbols[Index]);
GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t index) const {
return cast<GlobalSymbol>(symbols[index]);
}
EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const {
return cast<EventSymbol>(Symbols[Index]);
EventSymbol *ObjFile::getEventSymbol(uint32_t index) const {
return cast<EventSymbol>(symbols[index]);
}
SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
return cast<SectionSymbol>(Symbols[Index]);
SectionSymbol *ObjFile::getSectionSymbol(uint32_t index) const {
return cast<SectionSymbol>(symbols[index]);
}
DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const {
return cast<DataSymbol>(Symbols[Index]);
DataSymbol *ObjFile::getDataSymbol(uint32_t index) const {
return cast<DataSymbol>(symbols[index]);
}
Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
StringRef Name = Sym.Info.Name;
uint32_t Flags = Sym.Info.Flags;
Symbol *ObjFile::createDefined(const WasmSymbol &sym) {
StringRef name = sym.Info.Name;
uint32_t flags = sym.Info.Flags;
switch (Sym.Info.Kind) {
switch (sym.Info.Kind) {
case WASM_SYMBOL_TYPE_FUNCTION: {
InputFunction *Func =
Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()];
if (Func->Discarded)
InputFunction *func =
functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()];
if (func->discarded)
return nullptr;
if (Sym.isBindingLocal())
return make<DefinedFunction>(Name, Flags, this, Func);
return Symtab->addDefinedFunction(Name, Flags, this, Func);
if (sym.isBindingLocal())
return make<DefinedFunction>(name, flags, this, func);
return symtab->addDefinedFunction(name, flags, this, func);
}
case WASM_SYMBOL_TYPE_DATA: {
InputSegment *Seg = Segments[Sym.Info.DataRef.Segment];
if (Seg->Discarded)
InputSegment *seg = segments[sym.Info.DataRef.Segment];
if (seg->discarded)
return nullptr;
uint32_t Offset = Sym.Info.DataRef.Offset;
uint32_t Size = Sym.Info.DataRef.Size;
uint32_t offset = sym.Info.DataRef.Offset;
uint32_t size = sym.Info.DataRef.Size;
if (Sym.isBindingLocal())
return make<DefinedData>(Name, Flags, this, Seg, Offset, Size);
return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size);
if (sym.isBindingLocal())
return make<DefinedData>(name, flags, this, seg, offset, size);
return symtab->addDefinedData(name, flags, this, seg, offset, size);
}
case WASM_SYMBOL_TYPE_GLOBAL: {
InputGlobal *Global =
Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()];
if (Sym.isBindingLocal())
return make<DefinedGlobal>(Name, Flags, this, Global);
return Symtab->addDefinedGlobal(Name, Flags, this, Global);
InputGlobal *global =
globals[sym.Info.ElementIndex - wasmObj->getNumImportedGlobals()];
if (sym.isBindingLocal())
return make<DefinedGlobal>(name, flags, this, global);
return symtab->addDefinedGlobal(name, flags, this, global);
}
case WASM_SYMBOL_TYPE_SECTION: {
InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex];
assert(Sym.isBindingLocal());
return make<SectionSymbol>(Flags, Section, this);
InputSection *section = customSectionsByIndex[sym.Info.ElementIndex];
assert(sym.isBindingLocal());
return make<SectionSymbol>(flags, section, this);
}
case WASM_SYMBOL_TYPE_EVENT: {
InputEvent *Event =
Events[Sym.Info.ElementIndex - WasmObj->getNumImportedEvents()];
if (Sym.isBindingLocal())
return make<DefinedEvent>(Name, Flags, this, Event);
return Symtab->addDefinedEvent(Name, Flags, this, Event);
InputEvent *event =
events[sym.Info.ElementIndex - wasmObj->getNumImportedEvents()];
if (sym.isBindingLocal())
return make<DefinedEvent>(name, flags, this, event);
return symtab->addDefinedEvent(name, flags, this, event);
}
}
llvm_unreachable("unknown symbol kind");
}
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly) {
StringRef Name = Sym.Info.Name;
uint32_t Flags = Sym.Info.Flags;
Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) {
StringRef name = sym.Info.Name;
uint32_t flags = sym.Info.Flags;
switch (Sym.Info.Kind) {
switch (sym.Info.Kind) {
case WASM_SYMBOL_TYPE_FUNCTION:
if (Sym.isBindingLocal())
return make<UndefinedFunction>(Name, Sym.Info.ImportName,
Sym.Info.ImportModule, Flags, this,
Sym.Signature, IsCalledDirectly);
return Symtab->addUndefinedFunction(Name, Sym.Info.ImportName,
Sym.Info.ImportModule, Flags, this,
Sym.Signature, IsCalledDirectly);
if (sym.isBindingLocal())
return make<UndefinedFunction>(name, sym.Info.ImportName,
sym.Info.ImportModule, flags, this,
sym.Signature, isCalledDirectly);
return symtab->addUndefinedFunction(name, sym.Info.ImportName,
sym.Info.ImportModule, flags, this,
sym.Signature, isCalledDirectly);
case WASM_SYMBOL_TYPE_DATA:
if (Sym.isBindingLocal())
return make<UndefinedData>(Name, Flags, this);
return Symtab->addUndefinedData(Name, Flags, this);
if (sym.isBindingLocal())
return make<UndefinedData>(name, flags, this);
return symtab->addUndefinedData(name, flags, this);
case WASM_SYMBOL_TYPE_GLOBAL:
if (Sym.isBindingLocal())
return make<UndefinedGlobal>(Name, Sym.Info.ImportName,
Sym.Info.ImportModule, Flags, this,
Sym.GlobalType);
return Symtab->addUndefinedGlobal(Name, Sym.Info.ImportName,
Sym.Info.ImportModule, Flags, this,
Sym.GlobalType);
if (sym.isBindingLocal())
return make<UndefinedGlobal>(name, sym.Info.ImportName,
sym.Info.ImportModule, flags, this,
sym.GlobalType);
return symtab->addUndefinedGlobal(name, sym.Info.ImportName,
sym.Info.ImportModule, flags, this,
sym.GlobalType);
case WASM_SYMBOL_TYPE_SECTION:
llvm_unreachable("section symbols cannot be undefined");
}
@ -455,41 +455,41 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly) {
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
File = CHECK(Archive::create(MB), toString(this));
file = CHECK(Archive::create(mb), toString(this));
// Read the symbol table to construct Lazy symbols.
int Count = 0;
for (const Archive::Symbol &Sym : File->symbols()) {
Symtab->addLazy(this, &Sym);
++Count;
int count = 0;
for (const Archive::Symbol &sym : file->symbols()) {
symtab->addLazy(this, &sym);
++count;
}
LLVM_DEBUG(dbgs() << "Read " << Count << " symbols\n");
LLVM_DEBUG(dbgs() << "Read " << count << " symbols\n");
}
void ArchiveFile::addMember(const Archive::Symbol *Sym) {
const Archive::Child &C =
CHECK(Sym->getMember(),
"could not get the member for symbol " + Sym->getName());
void ArchiveFile::addMember(const Archive::Symbol *sym) {
const Archive::Child &c =
CHECK(sym->getMember(),
"could not get the member for symbol " + sym->getName());
// Don't try to load the same member twice (this can happen when members
// mutually reference each other).
if (!Seen.insert(C.getChildOffset()).second)
if (!seen.insert(c.getChildOffset()).second)
return;
LLVM_DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
LLVM_DEBUG(dbgs() << "loading lazy: " << sym->getName() << "\n");
LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
MemoryBufferRef MB =
CHECK(C.getMemoryBufferRef(),
MemoryBufferRef mb =
CHECK(c.getMemoryBufferRef(),
"could not get the buffer for the member defining symbol " +
Sym->getName());
sym->getName());
InputFile *Obj = createObjectFile(MB, getName());
Symtab->addFile(Obj);
InputFile *obj = createObjectFile(mb, getName());
symtab->addFile(obj);
}
static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
switch (GvVisibility) {
static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) {
switch (gvVisibility) {
case GlobalValue::DefaultVisibility:
return WASM_SYMBOL_VISIBILITY_DEFAULT;
case GlobalValue::HiddenVisibility:
@ -499,52 +499,52 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
llvm_unreachable("unknown visibility");
}
static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile &F) {
StringRef Name = Saver.save(ObjSym.getName());
static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
const lto::InputFile::Symbol &objSym,
BitcodeFile &f) {
StringRef name = saver.save(objSym.getName());
uint32_t Flags = ObjSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
Flags |= mapVisibility(ObjSym.getVisibility());
uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
flags |= mapVisibility(objSym.getVisibility());
int C = ObjSym.getComdatIndex();
bool ExcludedByComdat = C != -1 && !KeptComdats[C];
int c = objSym.getComdatIndex();
bool excludedByComdat = c != -1 && !keptComdats[c];
if (ObjSym.isUndefined() || ExcludedByComdat) {
if (ObjSym.isExecutable())
return Symtab->addUndefinedFunction(Name, Name, DefaultModule, Flags, &F,
if (objSym.isUndefined() || excludedByComdat) {
if (objSym.isExecutable())
return symtab->addUndefinedFunction(name, name, defaultModule, flags, &f,
nullptr, true);
return Symtab->addUndefinedData(Name, Flags, &F);
return symtab->addUndefinedData(name, flags, &f);
}
if (ObjSym.isExecutable())
return Symtab->addDefinedFunction(Name, Flags, &F, nullptr);
return Symtab->addDefinedData(Name, Flags, &F, nullptr, 0, 0);
if (objSym.isExecutable())
return symtab->addDefinedFunction(name, flags, &f, nullptr);
return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0);
}
void BitcodeFile::parse() {
Obj = check(lto::InputFile::create(MemoryBufferRef(
MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier()))));
Triple T(Obj->getTargetTriple());
if (T.getArch() != Triple::wasm32) {
error(toString(MB.getBufferIdentifier()) + ": machine type must be wasm32");
obj = check(lto::InputFile::create(MemoryBufferRef(
mb.getBuffer(), saver.save(archiveName + mb.getBufferIdentifier()))));
Triple t(obj->getTargetTriple());
if (t.getArch() != Triple::wasm32) {
error(toString(mb.getBufferIdentifier()) + ": machine type must be wasm32");
return;
}
std::vector<bool> KeptComdats;
for (StringRef S : Obj->getComdatTable())
KeptComdats.push_back(Symtab->addComdat(S));
std::vector<bool> keptComdats;
for (StringRef s : obj->getComdatTable())
keptComdats.push_back(symtab->addComdat(s));
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this));
for (const lto::InputFile::Symbol &objSym : obj->symbols())
symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this));
}
// Returns a string in the format of "foo.o" or "foo.a(bar.o)".
std::string lld::toString(const wasm::InputFile *File) {
if (!File)
std::string lld::toString(const wasm::InputFile *file) {
if (!file)
return "<internal>";
if (File->ArchiveName.empty())
return File->getName();
if (file->archiveName.empty())
return file->getName();
return (File->ArchiveName + "(" + File->getName() + ")").str();
return (file->archiveName + "(" + file->getName() + ")").str();
}

View File

@ -35,7 +35,7 @@ class InputSection;
// If --reproduce option is given, all input files are written
// to this tar archive.
extern std::unique_ptr<llvm::TarWriter> Tar;
extern std::unique_ptr<llvm::TarWriter> tar;
class InputFile {
public:
@ -49,129 +49,129 @@ public:
virtual ~InputFile() {}
// Returns the filename.
StringRef getName() const { return MB.getBufferIdentifier(); }
StringRef getName() const { return mb.getBufferIdentifier(); }
Kind kind() const { return FileKind; }
Kind kind() const { return fileKind; }
// An archive file name if this file is created from an archive.
StringRef ArchiveName;
StringRef archiveName;
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
ArrayRef<Symbol *> getSymbols() const { return symbols; }
MutableArrayRef<Symbol *> getMutableSymbols() { return Symbols; }
MutableArrayRef<Symbol *> getMutableSymbols() { return symbols; }
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
MemoryBufferRef MB;
InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}
MemoryBufferRef mb;
// List of all symbols referenced or defined by this file.
std::vector<Symbol *> Symbols;
std::vector<Symbol *> symbols;
private:
const Kind FileKind;
const Kind fileKind;
};
// .a file (ar archive)
class ArchiveFile : public InputFile {
public:
explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
explicit ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
void addMember(const llvm::object::Archive::Symbol *Sym);
void addMember(const llvm::object::Archive::Symbol *sym);
void parse();
private:
std::unique_ptr<llvm::object::Archive> File;
llvm::DenseSet<uint64_t> Seen;
std::unique_ptr<llvm::object::Archive> file;
llvm::DenseSet<uint64_t> seen;
};
// .o file (wasm object file)
class ObjFile : public InputFile {
public:
explicit ObjFile(MemoryBufferRef M, StringRef ArchiveName)
: InputFile(ObjectKind, M) {
this->ArchiveName = ArchiveName;
explicit ObjFile(MemoryBufferRef m, StringRef archiveName)
: InputFile(ObjectKind, m) {
this->archiveName = archiveName;
}
static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
void parse(bool IgnoreComdats = false);
void parse(bool ignoreComdats = false);
// Returns the underlying wasm file.
const WasmObjectFile *getWasmObj() const { return WasmObj.get(); }
const WasmObjectFile *getWasmObj() const { return wasmObj.get(); }
void dumpInfo() const;
uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
uint32_t calcNewValue(const WasmRelocation &Reloc) const;
uint32_t calcNewAddend(const WasmRelocation &Reloc) const;
uint32_t calcExpectedValue(const WasmRelocation &Reloc) const;
Symbol *getSymbol(const WasmRelocation &Reloc) const {
return Symbols[Reloc.Index];
uint32_t calcNewIndex(const WasmRelocation &reloc) const;
uint32_t calcNewValue(const WasmRelocation &reloc) const;
uint32_t calcNewAddend(const WasmRelocation &reloc) const;
uint32_t calcExpectedValue(const WasmRelocation &reloc) const;
Symbol *getSymbol(const WasmRelocation &reloc) const {
return symbols[reloc.Index];
};
const WasmSection *CodeSection = nullptr;
const WasmSection *DataSection = nullptr;
const WasmSection *codeSection = nullptr;
const WasmSection *dataSection = nullptr;
// Maps input type indices to output type indices
std::vector<uint32_t> TypeMap;
std::vector<bool> TypeIsUsed;
std::vector<uint32_t> typeMap;
std::vector<bool> typeIsUsed;
// Maps function indices to table indices
std::vector<uint32_t> TableEntries;
std::vector<bool> KeptComdats;
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
std::vector<InputGlobal *> Globals;
std::vector<InputEvent *> Events;
std::vector<InputSection *> CustomSections;
llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
std::vector<uint32_t> tableEntries;
std::vector<bool> keptComdats;
std::vector<InputSegment *> segments;
std::vector<InputFunction *> functions;
std::vector<InputGlobal *> globals;
std::vector<InputEvent *> events;
std::vector<InputSection *> customSections;
llvm::DenseMap<uint32_t, InputSection *> customSectionsByIndex;
Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
FunctionSymbol *getFunctionSymbol(uint32_t Index) const;
DataSymbol *getDataSymbol(uint32_t Index) const;
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
SectionSymbol *getSectionSymbol(uint32_t Index) const;
EventSymbol *getEventSymbol(uint32_t Index) const;
Symbol *getSymbol(uint32_t index) const { return symbols[index]; }
FunctionSymbol *getFunctionSymbol(uint32_t index) const;
DataSymbol *getDataSymbol(uint32_t index) const;
GlobalSymbol *getGlobalSymbol(uint32_t index) const;
SectionSymbol *getSectionSymbol(uint32_t index) const;
EventSymbol *getEventSymbol(uint32_t index) const;
private:
Symbol *createDefined(const WasmSymbol &Sym);
Symbol *createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly);
Symbol *createDefined(const WasmSymbol &sym);
Symbol *createUndefined(const WasmSymbol &sym, bool isCalledDirectly);
bool isExcludedByComdat(InputChunk *Chunk) const;
bool isExcludedByComdat(InputChunk *chunk) const;
std::unique_ptr<WasmObjectFile> WasmObj;
std::unique_ptr<WasmObjectFile> wasmObj;
};
// .so file.
class SharedFile : public InputFile {
public:
explicit SharedFile(MemoryBufferRef M) : InputFile(SharedKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == SharedKind; }
explicit SharedFile(MemoryBufferRef m) : InputFile(SharedKind, m) {}
static bool classof(const InputFile *f) { return f->kind() == SharedKind; }
};
// .bc file
class BitcodeFile : public InputFile {
public:
explicit BitcodeFile(MemoryBufferRef M, StringRef ArchiveName)
: InputFile(BitcodeKind, M) {
this->ArchiveName = ArchiveName;
explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName)
: InputFile(BitcodeKind, m) {
this->archiveName = archiveName;
}
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
void parse();
std::unique_ptr<llvm::lto::InputFile> Obj;
std::unique_ptr<llvm::lto::InputFile> obj;
};
// Will report a fatal() error if the input buffer is not a valid bitcode
// or wasm object file.
InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "");
InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "");
// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
llvm::Optional<MemoryBufferRef> readFile(StringRef path);
} // namespace wasm
std::string toString(const wasm::InputFile *File);
std::string toString(const wasm::InputFile *file);
} // namespace lld

View File

@ -22,32 +22,32 @@ namespace wasm {
// combined to form the final GLOBALS section.
class InputGlobal {
public:
InputGlobal(const WasmGlobal &G, ObjFile *F)
: File(F), Global(G), Live(!Config->GcSections) {}
InputGlobal(const WasmGlobal &g, ObjFile *f)
: file(f), global(g), live(!config->gcSections) {}
StringRef getName() const { return Global.SymbolName; }
const WasmGlobalType &getType() const { return Global.Type; }
StringRef getName() const { return global.SymbolName; }
const WasmGlobalType &getType() const { return global.Type; }
uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); }
bool hasGlobalIndex() const { return GlobalIndex.hasValue(); }
void setGlobalIndex(uint32_t Index) {
uint32_t getGlobalIndex() const { return globalIndex.getValue(); }
bool hasGlobalIndex() const { return globalIndex.hasValue(); }
void setGlobalIndex(uint32_t index) {
assert(!hasGlobalIndex());
GlobalIndex = Index;
globalIndex = index;
}
ObjFile *File;
WasmGlobal Global;
ObjFile *file;
WasmGlobal global;
bool Live = false;
bool live = false;
protected:
llvm::Optional<uint32_t> GlobalIndex;
llvm::Optional<uint32_t> globalIndex;
};
} // namespace wasm
inline std::string toString(const wasm::InputGlobal *G) {
return (toString(G->File) + ":(" + G->getName() + ")").str();
inline std::string toString(const wasm::InputGlobal *g) {
return (toString(g->file) + ":(" + g->getName() + ")").str();
}
} // namespace lld

View File

@ -40,127 +40,127 @@ using namespace lld;
using namespace lld::wasm;
static std::unique_ptr<lto::LTO> createLTO() {
lto::Config C;
C.Options = initTargetOptionsFromCodeGenFlags();
lto::Config c;
c.Options = initTargetOptionsFromCodeGenFlags();
// Always emit a section per function/data with LTO.
C.Options.FunctionSections = true;
C.Options.DataSections = true;
c.Options.FunctionSections = true;
c.Options.DataSections = true;
C.DisableVerify = Config->DisableVerify;
C.DiagHandler = diagnosticHandler;
C.OptLevel = Config->LTOO;
C.MAttrs = getMAttrs();
C.CGOptLevel = args::getCGOptLevel(Config->LTOO);
c.DisableVerify = config->disableVerify;
c.DiagHandler = diagnosticHandler;
c.OptLevel = config->ltoo;
c.MAttrs = getMAttrs();
c.CGOptLevel = args::getCGOptLevel(config->ltoo);
if (Config->Relocatable)
C.RelocModel = None;
else if (Config->Pic)
C.RelocModel = Reloc::PIC_;
if (config->relocatable)
c.RelocModel = None;
else if (config->isPic)
c.RelocModel = Reloc::PIC_;
else
C.RelocModel = Reloc::Static;
c.RelocModel = Reloc::Static;
if (Config->SaveTemps)
checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
if (config->saveTemps)
checkError(c.addSaveTemps(config->outputFile.str() + ".",
/*UseInputModulePath*/ true));
lto::ThinBackend Backend;
if (Config->ThinLTOJobs != -1U)
Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
return llvm::make_unique<lto::LTO>(std::move(C), Backend,
Config->LTOPartitions);
lto::ThinBackend backend;
if (config->thinLTOJobs != -1U)
backend = lto::createInProcessThinBackend(config->thinLTOJobs);
return llvm::make_unique<lto::LTO>(std::move(c), backend,
config->ltoPartitions);
}
BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::BitcodeCompiler() : ltoObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
static void undefine(Symbol *S) {
if (auto F = dyn_cast<DefinedFunction>(S))
replaceSymbol<UndefinedFunction>(F, F->getName(), F->getName(),
DefaultModule, 0,
F->getFile(), F->Signature);
else if (isa<DefinedData>(S))
replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
static void undefine(Symbol *s) {
if (auto f = dyn_cast<DefinedFunction>(s))
replaceSymbol<UndefinedFunction>(f, f->getName(), f->getName(),
defaultModule, 0,
f->getFile(), f->signature);
else if (isa<DefinedData>(s))
replaceSymbol<UndefinedData>(s, s->getName(), 0, s->getFile());
else
llvm_unreachable("unexpected symbol kind");
}
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
ArrayRef<Symbol *> Syms = F.getSymbols();
std::vector<lto::SymbolResolution> Resols(Syms.size());
void BitcodeCompiler::add(BitcodeFile &f) {
lto::InputFile &obj = *f.obj;
unsigned symNum = 0;
ArrayRef<Symbol *> syms = f.getSymbols();
std::vector<lto::SymbolResolution> resols(syms.size());
// Provide a resolution to the LTO API for each symbol.
for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
Symbol *Sym = Syms[SymNum];
lto::SymbolResolution &R = Resols[SymNum];
++SymNum;
for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
Symbol *sym = syms[symNum];
lto::SymbolResolution &r = resols[symNum];
++symNum;
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj ||
(R.Prevailing && Sym->isExported());
if (R.Prevailing)
undefine(Sym);
r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj ||
(r.Prevailing && sym->isExported());
if (r.Prevailing)
undefine(sym);
// We tell LTO to not apply interprocedural optimization for wrapped
// (with --wrap) symbols because otherwise LTO would inline them while
// their values are still not final.
R.LinkerRedefined = !Sym->CanInline;
r.LinkerRedefined = !sym->canInline;
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
checkError(ltoObj->add(std::move(f.obj), resols));
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
Buf.resize(MaxTasks);
Files.resize(MaxTasks);
unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks);
files.resize(maxTasks);
// The --thinlto-cache-dir option specifies the path to a directory in which
// to cache native object files for ThinLTO incremental builds. If a path was
// specified, configure LTO to use it as the cache directory.
lto::NativeObjectCache Cache;
if (!Config->ThinLTOCacheDir.empty())
Cache = check(
lto::localCache(Config->ThinLTOCacheDir,
[&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
Files[Task] = std::move(MB);
lto::NativeObjectCache cache;
if (!config->thinLTOCacheDir.empty())
cache = check(
lto::localCache(config->thinLTOCacheDir,
[&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
files[task] = std::move(mb);
}));
checkError(LTOObj->run(
[&](size_t Task) {
checkError(ltoObj->run(
[&](size_t task) {
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<raw_svector_ostream>(Buf[Task]));
llvm::make_unique<raw_svector_ostream>(buf[task]));
},
Cache));
cache));
if (!Config->ThinLTOCacheDir.empty())
pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
if (!config->thinLTOCacheDir.empty())
pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy);
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buf[I].empty())
std::vector<StringRef> ret;
for (unsigned i = 0; i != maxTasks; ++i) {
if (buf[i].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
if (config->saveTemps) {
if (i == 0)
saveBuffer(buf[i], config->outputFile + ".lto.o");
else
saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o");
}
Ret.emplace_back(Buf[I].data(), Buf[I].size());
ret.emplace_back(buf[i].data(), buf[i].size());
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(File->getBuffer());
for (std::unique_ptr<MemoryBuffer> &file : files)
if (file)
ret.push_back(file->getBuffer());
return Ret;
return ret;
}

View File

@ -43,13 +43,13 @@ public:
BitcodeCompiler();
~BitcodeCompiler();
void add(BitcodeFile &F);
void add(BitcodeFile &f);
std::vector<StringRef> compile();
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buf;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
std::unique_ptr<llvm::lto::LTO> ltoObj;
std::vector<SmallString<0>> buf;
std::vector<std::unique_ptr<MemoryBuffer>> files;
};
} // namespace wasm
} // namespace lld

View File

@ -32,68 +32,68 @@ using namespace llvm;
using namespace llvm::wasm;
void lld::wasm::markLive() {
if (!Config->GcSections)
if (!config->gcSections)
return;
LLVM_DEBUG(dbgs() << "markLive\n");
SmallVector<InputChunk *, 256> Q;
SmallVector<InputChunk *, 256> q;
std::function<void(Symbol*)> Enqueue = [&](Symbol *Sym) {
if (!Sym || Sym->isLive())
std::function<void(Symbol*)> enqueue = [&](Symbol *sym) {
if (!sym || sym->isLive())
return;
LLVM_DEBUG(dbgs() << "markLive: " << Sym->getName() << "\n");
Sym->markLive();
if (InputChunk *Chunk = Sym->getChunk())
Q.push_back(Chunk);
LLVM_DEBUG(dbgs() << "markLive: " << sym->getName() << "\n");
sym->markLive();
if (InputChunk *chunk = sym->getChunk())
q.push_back(chunk);
// The ctor functions are all referenced by the synthetic CallCtors
// function. However, this function does not contain relocations so we
// have to manually mark the ctors as live if CallCtors itself is live.
if (Sym == WasmSym::CallCtors) {
if (Config->PassiveSegments)
Enqueue(WasmSym::InitMemory);
if (Config->Pic)
Enqueue(WasmSym::ApplyRelocs);
for (const ObjFile *Obj : Symtab->ObjectFiles) {
const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
for (const WasmInitFunc &F : L.InitFunctions) {
auto* InitSym = Obj->getFunctionSymbol(F.Symbol);
if (!InitSym->isDiscarded())
Enqueue(InitSym);
if (sym == WasmSym::callCtors) {
if (config->passiveSegments)
enqueue(WasmSym::initMemory);
if (config->isPic)
enqueue(WasmSym::applyRelocs);
for (const ObjFile *obj : symtab->objectFiles) {
const WasmLinkingData &l = obj->getWasmObj()->linkingData();
for (const WasmInitFunc &f : l.InitFunctions) {
auto* initSym = obj->getFunctionSymbol(f.Symbol);
if (!initSym->isDiscarded())
enqueue(initSym);
}
}
}
};
// Add GC root symbols.
if (!Config->Entry.empty())
Enqueue(Symtab->find(Config->Entry));
if (!config->entry.empty())
enqueue(symtab->find(config->entry));
// We need to preserve any exported symbol
for (Symbol *Sym : Symtab->getSymbols())
if (Sym->isExported())
Enqueue(Sym);
for (Symbol *sym : symtab->getSymbols())
if (sym->isExported())
enqueue(sym);
// For relocatable output, we need to preserve all the ctor functions
if (Config->Relocatable) {
for (const ObjFile *Obj : Symtab->ObjectFiles) {
const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
for (const WasmInitFunc &F : L.InitFunctions)
Enqueue(Obj->getFunctionSymbol(F.Symbol));
if (config->relocatable) {
for (const ObjFile *obj : symtab->objectFiles) {
const WasmLinkingData &l = obj->getWasmObj()->linkingData();
for (const WasmInitFunc &f : l.InitFunctions)
enqueue(obj->getFunctionSymbol(f.Symbol));
}
}
if (Config->Pic)
Enqueue(WasmSym::CallCtors);
if (config->isPic)
enqueue(WasmSym::callCtors);
// Follow relocations to mark all reachable chunks.
while (!Q.empty()) {
InputChunk *C = Q.pop_back_val();
while (!q.empty()) {
InputChunk *c = q.pop_back_val();
for (const WasmRelocation Reloc : C->getRelocations()) {
if (Reloc.Type == R_WASM_TYPE_INDEX_LEB)
for (const WasmRelocation reloc : c->getRelocations()) {
if (reloc.Type == R_WASM_TYPE_INDEX_LEB)
continue;
Symbol *Sym = C->File->getSymbol(Reloc.Index);
Symbol *sym = c->file->getSymbol(reloc.Index);
// If the function has been assigned the special index zero in the table,
// the relocation doesn't pull in the function body, since the function
@ -102,38 +102,38 @@ void lld::wasm::markLive() {
// zero is only reachable via "call", not via "call_indirect". The stub
// functions used for weak-undefined symbols have this behaviour (compare
// equal to null pointer, only reachable via direct call).
if (Reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
Reloc.Type == R_WASM_TABLE_INDEX_I32) {
auto *FuncSym = cast<FunctionSymbol>(Sym);
if (FuncSym->hasTableIndex() && FuncSym->getTableIndex() == 0)
if (reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
reloc.Type == R_WASM_TABLE_INDEX_I32) {
auto *funcSym = cast<FunctionSymbol>(sym);
if (funcSym->hasTableIndex() && funcSym->getTableIndex() == 0)
continue;
}
Enqueue(Sym);
enqueue(sym);
}
}
// Report garbage-collected sections.
if (Config->PrintGcSections) {
for (const ObjFile *Obj : Symtab->ObjectFiles) {
for (InputChunk *C : Obj->Functions)
if (!C->Live)
message("removing unused section " + toString(C));
for (InputChunk *C : Obj->Segments)
if (!C->Live)
message("removing unused section " + toString(C));
for (InputGlobal *G : Obj->Globals)
if (!G->Live)
message("removing unused section " + toString(G));
for (InputEvent *E : Obj->Events)
if (!E->Live)
message("removing unused section " + toString(E));
if (config->printGcSections) {
for (const ObjFile *obj : symtab->objectFiles) {
for (InputChunk *c : obj->functions)
if (!c->live)
message("removing unused section " + toString(c));
for (InputChunk *c : obj->segments)
if (!c->live)
message("removing unused section " + toString(c));
for (InputGlobal *g : obj->globals)
if (!g->live)
message("removing unused section " + toString(g));
for (InputEvent *e : obj->events)
if (!e->live)
message("removing unused section " + toString(e));
}
for (InputChunk *C : Symtab->SyntheticFunctions)
if (!C->Live)
message("removing unused section " + toString(C));
for (InputGlobal *G : Symtab->SyntheticGlobals)
if (!G->Live)
message("removing unused section " + toString(G));
for (InputChunk *c : symtab->syntheticFunctions)
if (!c->live)
message("removing unused section " + toString(c));
for (InputGlobal *g : symtab->syntheticGlobals)
if (!g->live)
message("removing unused section " + toString(g));
}
}

View File

@ -23,8 +23,8 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
static StringRef sectionTypeToString(uint32_t SectionType) {
switch (SectionType) {
static StringRef sectionTypeToString(uint32_t sectionType) {
switch (sectionType) {
case WASM_SEC_CUSTOM:
return "CUSTOM";
case WASM_SEC_TYPE:
@ -59,192 +59,192 @@ static StringRef sectionTypeToString(uint32_t SectionType) {
}
// Returns a string, e.g. "FUNCTION(.text)".
std::string lld::toString(const OutputSection &Sec) {
if (!Sec.Name.empty())
return (Sec.getSectionName() + "(" + Sec.Name + ")").str();
return Sec.getSectionName();
std::string lld::toString(const OutputSection &sec) {
if (!sec.name.empty())
return (sec.getSectionName() + "(" + sec.name + ")").str();
return sec.getSectionName();
}
StringRef OutputSection::getSectionName() const {
return sectionTypeToString(Type);
return sectionTypeToString(type);
}
void OutputSection::createHeader(size_t BodySize) {
raw_string_ostream OS(Header);
debugWrite(OS.tell(), "section type [" + getSectionName() + "]");
encodeULEB128(Type, OS);
writeUleb128(OS, BodySize, "section size");
OS.flush();
log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
void OutputSection::createHeader(size_t bodySize) {
raw_string_ostream os(header);
debugWrite(os.tell(), "section type [" + getSectionName() + "]");
encodeULEB128(type, os);
writeUleb128(os, bodySize, "section size");
os.flush();
log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) +
" total=" + Twine(getSize()));
}
void CodeSection::finalizeContents() {
raw_string_ostream OS(CodeSectionHeader);
writeUleb128(OS, Functions.size(), "function count");
OS.flush();
BodySize = CodeSectionHeader.size();
raw_string_ostream os(codeSectionHeader);
writeUleb128(os, functions.size(), "function count");
os.flush();
bodySize = codeSectionHeader.size();
for (InputFunction *Func : Functions) {
Func->OutputOffset = BodySize;
Func->calculateSize();
BodySize += Func->getSize();
for (InputFunction *func : functions) {
func->outputOffset = bodySize;
func->calculateSize();
bodySize += func->getSize();
}
createHeader(BodySize);
createHeader(bodySize);
}
void CodeSection::writeTo(uint8_t *Buf) {
void CodeSection::writeTo(uint8_t *buf) {
log("writing " + toString(*this));
log(" size=" + Twine(getSize()));
log(" headersize=" + Twine(Header.size()));
log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
Buf += Offset;
log(" headersize=" + Twine(header.size()));
log(" codeheadersize=" + Twine(codeSectionHeader.size()));
buf += offset;
// Write section header
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
memcpy(buf, header.data(), header.size());
buf += header.size();
// Write code section headers
memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size());
// Write code section bodies
for (const InputChunk *Chunk : Functions)
Chunk->writeTo(Buf);
for (const InputChunk *chunk : functions)
chunk->writeTo(buf);
}
uint32_t CodeSection::getNumRelocations() const {
uint32_t Count = 0;
for (const InputChunk *Func : Functions)
Count += Func->getNumRelocations();
return Count;
uint32_t count = 0;
for (const InputChunk *func : functions)
count += func->getNumRelocations();
return count;
}
void CodeSection::writeRelocations(raw_ostream &OS) const {
for (const InputChunk *C : Functions)
C->writeRelocations(OS);
void CodeSection::writeRelocations(raw_ostream &os) const {
for (const InputChunk *c : functions)
c->writeRelocations(os);
}
void DataSection::finalizeContents() {
raw_string_ostream OS(DataSectionHeader);
raw_string_ostream os(dataSectionHeader);
writeUleb128(OS, Segments.size(), "data segment count");
OS.flush();
BodySize = DataSectionHeader.size();
writeUleb128(os, segments.size(), "data segment count");
os.flush();
bodySize = dataSectionHeader.size();
assert((!Config->Pic || Segments.size() <= 1) &&
assert((!config->isPic || segments.size() <= 1) &&
"Currenly only a single data segment is supported in PIC mode");
for (OutputSegment *Segment : Segments) {
raw_string_ostream OS(Segment->Header);
writeUleb128(OS, Segment->InitFlags, "init flags");
if (Segment->InitFlags & WASM_SEGMENT_HAS_MEMINDEX)
writeUleb128(OS, 0, "memory index");
if ((Segment->InitFlags & WASM_SEGMENT_IS_PASSIVE) == 0) {
WasmInitExpr InitExpr;
if (Config->Pic) {
InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
for (OutputSegment *segment : segments) {
raw_string_ostream os(segment->header);
writeUleb128(os, segment->initFlags, "init flags");
if (segment->initFlags & WASM_SEGMENT_HAS_MEMINDEX)
writeUleb128(os, 0, "memory index");
if ((segment->initFlags & WASM_SEGMENT_IS_PASSIVE) == 0) {
WasmInitExpr initExpr;
if (config->isPic) {
initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex();
} else {
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
InitExpr.Value.Int32 = Segment->StartVA;
initExpr.Opcode = WASM_OPCODE_I32_CONST;
initExpr.Value.Int32 = segment->startVA;
}
writeInitExpr(OS, InitExpr);
writeInitExpr(os, initExpr);
}
writeUleb128(OS, Segment->Size, "segment size");
OS.flush();
writeUleb128(os, segment->size, "segment size");
os.flush();
Segment->SectionOffset = BodySize;
BodySize += Segment->Header.size() + Segment->Size;
log("Data segment: size=" + Twine(Segment->Size) + ", startVA=" +
Twine::utohexstr(Segment->StartVA) + ", name=" + Segment->Name);
segment->sectionOffset = bodySize;
bodySize += segment->header.size() + segment->size;
log("Data segment: size=" + Twine(segment->size) + ", startVA=" +
Twine::utohexstr(segment->startVA) + ", name=" + segment->name);
for (InputSegment *InputSeg : Segment->InputSegments)
InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
InputSeg->OutputSegmentOffset;
for (InputSegment *inputSeg : segment->inputSegments)
inputSeg->outputOffset = segment->sectionOffset + segment->header.size() +
inputSeg->outputSegmentOffset;
}
createHeader(BodySize);
createHeader(bodySize);
}
void DataSection::writeTo(uint8_t *Buf) {
void DataSection::writeTo(uint8_t *buf) {
log("writing " + toString(*this) + " size=" + Twine(getSize()) +
" body=" + Twine(BodySize));
Buf += Offset;
" body=" + Twine(bodySize));
buf += offset;
// Write section header
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
memcpy(buf, header.data(), header.size());
buf += header.size();
// Write data section headers
memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());
for (const OutputSegment *Segment : Segments) {
for (const OutputSegment *segment : segments) {
// Write data segment header
uint8_t *SegStart = Buf + Segment->SectionOffset;
memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
uint8_t *segStart = buf + segment->sectionOffset;
memcpy(segStart, segment->header.data(), segment->header.size());
// Write segment data payload
for (const InputChunk *Chunk : Segment->InputSegments)
Chunk->writeTo(Buf);
for (const InputChunk *chunk : segment->inputSegments)
chunk->writeTo(buf);
}
}
uint32_t DataSection::getNumRelocations() const {
uint32_t Count = 0;
for (const OutputSegment *Seg : Segments)
for (const InputChunk *InputSeg : Seg->InputSegments)
Count += InputSeg->getNumRelocations();
return Count;
uint32_t count = 0;
for (const OutputSegment *seg : segments)
for (const InputChunk *inputSeg : seg->inputSegments)
count += inputSeg->getNumRelocations();
return count;
}
void DataSection::writeRelocations(raw_ostream &OS) const {
for (const OutputSegment *Seg : Segments)
for (const InputChunk *C : Seg->InputSegments)
C->writeRelocations(OS);
void DataSection::writeRelocations(raw_ostream &os) const {
for (const OutputSegment *seg : segments)
for (const InputChunk *c : seg->inputSegments)
c->writeRelocations(os);
}
void CustomSection::finalizeContents() {
raw_string_ostream OS(NameData);
encodeULEB128(Name.size(), OS);
OS << Name;
OS.flush();
raw_string_ostream os(nameData);
encodeULEB128(name.size(), os);
os << name;
os.flush();
for (InputSection *Section : InputSections) {
Section->OutputOffset = PayloadSize;
Section->OutputSec = this;
PayloadSize += Section->getSize();
for (InputSection *section : inputSections) {
section->outputOffset = payloadSize;
section->outputSec = this;
payloadSize += section->getSize();
}
createHeader(PayloadSize + NameData.size());
createHeader(payloadSize + nameData.size());
}
void CustomSection::writeTo(uint8_t *Buf) {
void CustomSection::writeTo(uint8_t *buf) {
log("writing " + toString(*this) + " size=" + Twine(getSize()) +
" chunks=" + Twine(InputSections.size()));
" chunks=" + Twine(inputSections.size()));
assert(Offset);
Buf += Offset;
assert(offset);
buf += offset;
// Write section header
memcpy(Buf, Header.data(), Header.size());
Buf += Header.size();
memcpy(Buf, NameData.data(), NameData.size());
Buf += NameData.size();
memcpy(buf, header.data(), header.size());
buf += header.size();
memcpy(buf, nameData.data(), nameData.size());
buf += nameData.size();
// Write custom sections payload
for (const InputSection *Section : InputSections)
Section->writeTo(Buf);
for (const InputSection *section : inputSections)
section->writeTo(buf);
}
uint32_t CustomSection::getNumRelocations() const {
uint32_t Count = 0;
for (const InputSection *InputSect : InputSections)
Count += InputSect->getNumRelocations();
return Count;
uint32_t count = 0;
for (const InputSection *inputSect : inputSections)
count += inputSect->getNumRelocations();
return count;
}
void CustomSection::writeRelocations(raw_ostream &OS) const {
for (const InputSection *S : InputSections)
S->writeRelocations(OS);
void CustomSection::writeRelocations(raw_ostream &os) const {
for (const InputSection *s : inputSections)
s->writeRelocations(os);
}

View File

@ -20,7 +20,7 @@ namespace lld {
namespace wasm {
class OutputSection;
}
std::string toString(const wasm::OutputSection &Section);
std::string toString(const wasm::OutputSection &section);
namespace wasm {
@ -28,67 +28,67 @@ class OutputSegment;
class OutputSection {
public:
OutputSection(uint32_t Type, std::string Name = "")
: Type(Type), Name(Name) {}
OutputSection(uint32_t type, std::string name = "")
: type(type), name(name) {}
virtual ~OutputSection() = default;
StringRef getSectionName() const;
void setOffset(size_t NewOffset) {
log("setOffset: " + toString(*this) + ": " + Twine(NewOffset));
Offset = NewOffset;
void setOffset(size_t newOffset) {
log("setOffset: " + toString(*this) + ": " + Twine(newOffset));
offset = newOffset;
}
void createHeader(size_t BodySize);
void createHeader(size_t bodySize);
virtual bool isNeeded() const { return true; }
virtual size_t getSize() const = 0;
virtual void writeTo(uint8_t *Buf) = 0;
virtual void writeTo(uint8_t *buf) = 0;
virtual void finalizeContents() = 0;
virtual uint32_t getNumRelocations() const { return 0; }
virtual void writeRelocations(raw_ostream &OS) const {}
virtual void writeRelocations(raw_ostream &os) const {}
std::string Header;
uint32_t Type;
uint32_t SectionIndex = UINT32_MAX;
std::string Name;
OutputSectionSymbol *SectionSym = nullptr;
std::string header;
uint32_t type;
uint32_t sectionIndex = UINT32_MAX;
std::string name;
OutputSectionSymbol *sectionSym = nullptr;
protected:
size_t Offset = 0;
size_t offset = 0;
};
class CodeSection : public OutputSection {
public:
explicit CodeSection(ArrayRef<InputFunction *> Functions)
: OutputSection(llvm::wasm::WASM_SEC_CODE), Functions(Functions) {}
explicit CodeSection(ArrayRef<InputFunction *> functions)
: OutputSection(llvm::wasm::WASM_SEC_CODE), functions(functions) {}
size_t getSize() const override { return Header.size() + BodySize; }
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return header.size() + bodySize; }
void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
void writeRelocations(raw_ostream &OS) const override;
bool isNeeded() const override { return Functions.size() > 0; }
void writeRelocations(raw_ostream &os) const override;
bool isNeeded() const override { return functions.size() > 0; }
void finalizeContents() override;
protected:
ArrayRef<InputFunction *> Functions;
std::string CodeSectionHeader;
size_t BodySize = 0;
ArrayRef<InputFunction *> functions;
std::string codeSectionHeader;
size_t bodySize = 0;
};
class DataSection : public OutputSection {
public:
explicit DataSection(ArrayRef<OutputSegment *> Segments)
: OutputSection(llvm::wasm::WASM_SEC_DATA), Segments(Segments) {}
explicit DataSection(ArrayRef<OutputSegment *> segments)
: OutputSection(llvm::wasm::WASM_SEC_DATA), segments(segments) {}
size_t getSize() const override { return Header.size() + BodySize; }
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return header.size() + bodySize; }
void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
void writeRelocations(raw_ostream &OS) const override;
bool isNeeded() const override { return Segments.size() > 0; }
void writeRelocations(raw_ostream &os) const override;
bool isNeeded() const override { return segments.size() > 0; }
void finalizeContents() override;
protected:
ArrayRef<OutputSegment *> Segments;
std::string DataSectionHeader;
size_t BodySize = 0;
ArrayRef<OutputSegment *> segments;
std::string dataSectionHeader;
size_t bodySize = 0;
};
// Represents a custom section in the output file. Wasm custom sections are
@ -100,21 +100,21 @@ protected:
// separately and are instead synthesized by the linker.
class CustomSection : public OutputSection {
public:
CustomSection(std::string Name, ArrayRef<InputSection *> InputSections)
: OutputSection(llvm::wasm::WASM_SEC_CUSTOM, Name),
InputSections(InputSections) {}
CustomSection(std::string name, ArrayRef<InputSection *> inputSections)
: OutputSection(llvm::wasm::WASM_SEC_CUSTOM, name),
inputSections(inputSections) {}
size_t getSize() const override {
return Header.size() + NameData.size() + PayloadSize;
return header.size() + nameData.size() + payloadSize;
}
void writeTo(uint8_t *Buf) override;
void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
void writeRelocations(raw_ostream &OS) const override;
void writeRelocations(raw_ostream &os) const override;
void finalizeContents() override;
protected:
size_t PayloadSize = 0;
ArrayRef<InputSection *> InputSections;
std::string NameData;
size_t payloadSize = 0;
ArrayRef<InputSection *> inputSections;
std::string nameData;
};
} // namespace wasm

View File

@ -20,30 +20,30 @@ class InputSegment;
class OutputSegment {
public:
OutputSegment(StringRef N, uint32_t Index) : Name(N), Index(Index) {}
OutputSegment(StringRef n, uint32_t index) : name(n), index(index) {}
void addInputSegment(InputSegment *InSeg) {
Alignment = std::max(Alignment, InSeg->getAlignment());
InputSegments.push_back(InSeg);
Size = llvm::alignTo(Size, 1ULL << InSeg->getAlignment());
InSeg->OutputSeg = this;
InSeg->OutputSegmentOffset = Size;
Size += InSeg->getSize();
void addInputSegment(InputSegment *inSeg) {
alignment = std::max(alignment, inSeg->getAlignment());
inputSegments.push_back(inSeg);
size = llvm::alignTo(size, 1ULL << inSeg->getAlignment());
inSeg->outputSeg = this;
inSeg->outputSegmentOffset = size;
size += inSeg->getSize();
}
StringRef Name;
const uint32_t Index;
uint32_t InitFlags = 0;
uint32_t SectionOffset = 0;
uint32_t Alignment = 0;
uint32_t StartVA = 0;
std::vector<InputSegment *> InputSegments;
StringRef name;
const uint32_t index;
uint32_t initFlags = 0;
uint32_t sectionOffset = 0;
uint32_t alignment = 0;
uint32_t startVA = 0;
std::vector<InputSegment *> inputSegments;
// Sum of the size of the all the input segments
uint32_t Size = 0;
uint32_t size = 0;
// Segment header
std::string Header;
std::string header;
};
} // namespace wasm

View File

@ -17,69 +17,69 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
static bool requiresGOTAccess(const Symbol *Sym) {
return Config->Pic && !Sym->isHidden() && !Sym->isLocal();
static bool requiresGOTAccess(const Symbol *sym) {
return config->isPic && !sym->isHidden() && !sym->isLocal();
}
static bool allowUndefined(const Symbol* Sym) {
static bool allowUndefined(const Symbol* sym) {
// Historically --allow-undefined doesn't work for data symbols since we don't
// have any way to represent these as imports in the final binary. The idea
// behind allowing undefined symbols is to allow importing these symbols from
// the embedder and we can't do this for data symbols (at least not without
// compiling with -fPIC)
if (isa<DataSymbol>(Sym))
if (isa<DataSymbol>(sym))
return false;
return (Config->AllowUndefined ||
Config->AllowUndefinedSymbols.count(Sym->getName()) != 0);
return (config->allowUndefined ||
config->allowUndefinedSymbols.count(sym->getName()) != 0);
}
static void reportUndefined(const Symbol* Sym) {
assert(Sym->isUndefined());
assert(!Sym->isWeak());
if (!allowUndefined(Sym))
error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
static void reportUndefined(const Symbol* sym) {
assert(sym->isUndefined());
assert(!sym->isWeak());
if (!allowUndefined(sym))
error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
}
void lld::wasm::scanRelocations(InputChunk *Chunk) {
if (!Chunk->Live)
void lld::wasm::scanRelocations(InputChunk *chunk) {
if (!chunk->live)
return;
ObjFile *File = Chunk->File;
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) {
ObjFile *file = chunk->file;
ArrayRef<WasmSignature> types = file->getWasmObj()->types();
for (const WasmRelocation &reloc : chunk->getRelocations()) {
if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
// Mark target type as live
File->TypeMap[Reloc.Index] =
Out.TypeSec->registerType(Types[Reloc.Index]);
File->TypeIsUsed[Reloc.Index] = true;
file->typeMap[reloc.Index] =
out.typeSec->registerType(types[reloc.Index]);
file->typeIsUsed[reloc.Index] = true;
continue;
}
// Other relocation types all have a corresponding symbol
Symbol *Sym = File->getSymbols()[Reloc.Index];
Symbol *sym = file->getSymbols()[reloc.Index];
switch (Reloc.Type) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
if (requiresGOTAccess(Sym))
if (requiresGOTAccess(sym))
break;
Out.ElemSec->addEntry(cast<FunctionSymbol>(Sym));
out.elemSec->addEntry(cast<FunctionSymbol>(sym));
break;
case R_WASM_GLOBAL_INDEX_LEB:
if (!isa<GlobalSymbol>(Sym))
Out.ImportSec->addGOTEntry(Sym);
if (!isa<GlobalSymbol>(sym))
out.importSec->addGOTEntry(sym);
break;
}
if (Config->Pic) {
switch (Reloc.Type) {
if (config->isPic) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_LEB:
// Certain relocation types can't be used when building PIC output,
// since they would require absolute symbol addresses at link time.
error(toString(File) + ": relocation " + relocTypeToString(Reloc.Type) +
" cannot be used against symbol " + toString(*Sym) +
error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
" cannot be used against symbol " + toString(*sym) +
"; recompile with -fPIC");
break;
case R_WASM_TABLE_INDEX_I32:
@ -87,14 +87,14 @@ void lld::wasm::scanRelocations(InputChunk *Chunk) {
// These relocation types are only present in the data section and
// will be converted into code by `generateRelocationCode`. This code
// requires the symbols to have GOT entires.
if (requiresGOTAccess(Sym))
Out.ImportSec->addGOTEntry(Sym);
if (requiresGOTAccess(sym))
out.importSec->addGOTEntry(sym);
break;
}
} else {
// Report undefined symbols
if (Sym->isUndefined() && !Config->Relocatable && !Sym->isWeak())
reportUndefined(Sym);
if (sym->isUndefined() && !config->relocatable && !sym->isWeak())
reportUndefined(sym);
}
}

View File

@ -14,7 +14,7 @@ namespace wasm {
class InputChunk;
void scanRelocations(InputChunk *Chunk);
void scanRelocations(InputChunk *chunk);
} // namespace wasm
} // namespace lld

File diff suppressed because it is too large Load Diff

View File

@ -35,89 +35,89 @@ class InputSegment;
// There is one add* function per symbol type.
class SymbolTable {
public:
void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
void wrap(Symbol *sym, Symbol *real, Symbol *wrap);
void addFile(InputFile *File);
void addFile(InputFile *file);
void addCombinedLTOObject();
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
ArrayRef<Symbol *> getSymbols() const { return symVector; }
Symbol *find(StringRef Name);
Symbol *find(StringRef name);
void replace(StringRef Name, Symbol* Sym);
void replace(StringRef name, Symbol* sym);
void trace(StringRef Name);
void trace(StringRef name);
Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
InputFunction *Function);
Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File,
InputSegment *Segment, uint32_t Address,
uint32_t Size);
Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
InputGlobal *G);
Symbol *addDefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
InputEvent *E);
Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file,
InputFunction *function);
Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file,
InputSegment *segment, uint32_t address,
uint32_t size);
Symbol *addDefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
InputGlobal *g);
Symbol *addDefinedEvent(StringRef name, uint32_t flags, InputFile *file,
InputEvent *e);
Symbol *addUndefinedFunction(StringRef Name, StringRef ImportName,
StringRef ImportModule, uint32_t Flags,
InputFile *File, const WasmSignature *Signature,
bool IsCalledDirectly);
Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File);
Symbol *addUndefinedGlobal(StringRef Name, StringRef ImportName,
StringRef ImportModule, uint32_t Flags,
InputFile *File, const WasmGlobalType *Type);
Symbol *addUndefinedFunction(StringRef name, StringRef importName,
StringRef importModule, uint32_t flags,
InputFile *file, const WasmSignature *signature,
bool isCalledDirectly);
Symbol *addUndefinedData(StringRef name, uint32_t flags, InputFile *file);
Symbol *addUndefinedGlobal(StringRef name, StringRef importName,
StringRef importModule, uint32_t flags,
InputFile *file, const WasmGlobalType *type);
void addLazy(ArchiveFile *F, const llvm::object::Archive::Symbol *Sym);
void addLazy(ArchiveFile *f, const llvm::object::Archive::Symbol *sym);
bool addComdat(StringRef Name);
bool addComdat(StringRef name);
DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags);
DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags,
InputGlobal *Global);
DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags,
InputFunction *Function);
DefinedData *addOptionalDataSymbol(StringRef Name, uint32_t Value = 0,
uint32_t Flags = 0);
DefinedData *addSyntheticDataSymbol(StringRef name, uint32_t flags);
DefinedGlobal *addSyntheticGlobal(StringRef name, uint32_t flags,
InputGlobal *global);
DefinedFunction *addSyntheticFunction(StringRef name, uint32_t flags,
InputFunction *function);
DefinedData *addOptionalDataSymbol(StringRef name, uint32_t value = 0,
uint32_t flags = 0);
void handleSymbolVariants();
void handleWeakUndefines();
std::vector<ObjFile *> ObjectFiles;
std::vector<SharedFile *> SharedFiles;
std::vector<BitcodeFile *> BitcodeFiles;
std::vector<InputFunction *> SyntheticFunctions;
std::vector<InputGlobal *> SyntheticGlobals;
std::vector<ObjFile *> objectFiles;
std::vector<SharedFile *> sharedFiles;
std::vector<BitcodeFile *> bitcodeFiles;
std::vector<InputFunction *> syntheticFunctions;
std::vector<InputGlobal *> syntheticGlobals;
private:
std::pair<Symbol *, bool> insert(StringRef Name, const InputFile *File);
std::pair<Symbol *, bool> insertName(StringRef Name);
std::pair<Symbol *, bool> insert(StringRef name, const InputFile *file);
std::pair<Symbol *, bool> insertName(StringRef name);
bool getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
const InputFile *File, Symbol **Out);
InputFunction *replaceWithUnreachable(Symbol *Sym, const WasmSignature &Sig,
StringRef DebugName);
bool getFunctionVariant(Symbol* sym, const WasmSignature *sig,
const InputFile *file, Symbol **out);
InputFunction *replaceWithUnreachable(Symbol *sym, const WasmSignature &sig,
StringRef debugName);
// Maps symbol names to index into the SymVector. -1 means that symbols
// is to not yet in the vector but it should have tracing enabled if it is
// ever added.
llvm::DenseMap<llvm::CachedHashStringRef, int> SymMap;
std::vector<Symbol *> SymVector;
llvm::DenseMap<llvm::CachedHashStringRef, int> symMap;
std::vector<Symbol *> symVector;
// For certain symbols types, e.g. function symbols, we allow for muliple
// variants of the same symbol with different signatures.
llvm::DenseMap<llvm::CachedHashStringRef, std::vector<Symbol *>> SymVariants;
llvm::DenseMap<llvm::CachedHashStringRef, std::vector<Symbol *>> symVariants;
// Comdat groups define "link once" sections. If two comdat groups have the
// same name, only one of them is linked, and the other is ignored. This set
// is used to uniquify them.
llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
llvm::DenseSet<llvm::CachedHashStringRef> comdatGroups;
// For LTO.
std::unique_ptr<BitcodeCompiler> LTO;
std::unique_ptr<BitcodeCompiler> lto;
};
extern SymbolTable *Symtab;
extern SymbolTable *symtab;
} // namespace wasm
} // namespace lld

View File

@ -24,16 +24,16 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
DefinedFunction *WasmSym::CallCtors;
DefinedFunction *WasmSym::InitMemory;
DefinedFunction *WasmSym::ApplyRelocs;
DefinedData *WasmSym::DsoHandle;
DefinedData *WasmSym::DataEnd;
DefinedData *WasmSym::GlobalBase;
DefinedData *WasmSym::HeapBase;
GlobalSymbol *WasmSym::StackPointer;
UndefinedGlobal *WasmSym::TableBase;
UndefinedGlobal *WasmSym::MemoryBase;
DefinedFunction *WasmSym::callCtors;
DefinedFunction *WasmSym::initMemory;
DefinedFunction *WasmSym::applyRelocs;
DefinedData *WasmSym::dsoHandle;
DefinedData *WasmSym::dataEnd;
DefinedData *WasmSym::globalBase;
DefinedData *WasmSym::heapBase;
GlobalSymbol *WasmSym::stackPointer;
UndefinedGlobal *WasmSym::tableBase;
UndefinedGlobal *WasmSym::memoryBase;
WasmSymbolType Symbol::getWasmType() const {
if (isa<FunctionSymbol>(this))
@ -50,248 +50,248 @@ WasmSymbolType Symbol::getWasmType() const {
}
const WasmSignature *Symbol::getSignature() const {
if (auto* F = dyn_cast<FunctionSymbol>(this))
return F->Signature;
if (auto *L = dyn_cast<LazySymbol>(this))
return L->Signature;
if (auto* f = dyn_cast<FunctionSymbol>(this))
return f->signature;
if (auto *l = dyn_cast<LazySymbol>(this))
return l->signature;
return nullptr;
}
InputChunk *Symbol::getChunk() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
return F->Function;
if (auto *D = dyn_cast<DefinedData>(this))
return D->Segment;
if (auto *f = dyn_cast<DefinedFunction>(this))
return f->function;
if (auto *d = dyn_cast<DefinedData>(this))
return d->segment;
return nullptr;
}
bool Symbol::isDiscarded() const {
if (InputChunk *C = getChunk())
return C->Discarded;
if (InputChunk *c = getChunk())
return c->discarded;
return false;
}
bool Symbol::isLive() const {
if (auto *G = dyn_cast<DefinedGlobal>(this))
return G->Global->Live;
if (auto *E = dyn_cast<DefinedEvent>(this))
return E->Event->Live;
if (InputChunk *C = getChunk())
return C->Live;
return Referenced;
if (auto *g = dyn_cast<DefinedGlobal>(this))
return g->global->live;
if (auto *e = dyn_cast<DefinedEvent>(this))
return e->event->live;
if (InputChunk *c = getChunk())
return c->live;
return referenced;
}
void Symbol::markLive() {
assert(!isDiscarded());
if (auto *G = dyn_cast<DefinedGlobal>(this))
G->Global->Live = true;
if (auto *E = dyn_cast<DefinedEvent>(this))
E->Event->Live = true;
if (InputChunk *C = getChunk())
C->Live = true;
Referenced = true;
if (auto *g = dyn_cast<DefinedGlobal>(this))
g->global->live = true;
if (auto *e = dyn_cast<DefinedEvent>(this))
e->event->live = true;
if (InputChunk *c = getChunk())
c->live = true;
referenced = true;
}
uint32_t Symbol::getOutputSymbolIndex() const {
assert(OutputSymbolIndex != INVALID_INDEX);
return OutputSymbolIndex;
assert(outputSymbolIndex != INVALID_INDEX);
return outputSymbolIndex;
}
void Symbol::setOutputSymbolIndex(uint32_t Index) {
LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index
void Symbol::setOutputSymbolIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
<< "\n");
assert(OutputSymbolIndex == INVALID_INDEX);
OutputSymbolIndex = Index;
assert(outputSymbolIndex == INVALID_INDEX);
outputSymbolIndex = index;
}
void Symbol::setGOTIndex(uint32_t Index) {
LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
assert(GOTIndex == INVALID_INDEX);
void Symbol::setGOTIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
assert(gotIndex == INVALID_INDEX);
// Any symbol that is assigned a GOT entry must be exported othewise the
// dynamic linker won't be able create the entry that contains it.
ForceExport = true;
GOTIndex = Index;
forceExport = true;
gotIndex = index;
}
bool Symbol::isWeak() const {
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
}
bool Symbol::isLocal() const {
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
}
bool Symbol::isHidden() const {
return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
}
void Symbol::setHidden(bool IsHidden) {
LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
if (IsHidden)
Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
void Symbol::setHidden(bool isHidden) {
LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
if (isHidden)
flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
else
Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
}
bool Symbol::isExported() const {
if (!isDefined() || isLocal())
return false;
if (ForceExport || Config->ExportAll)
if (forceExport || config->exportAll)
return true;
if (Config->ExportDynamic && !isHidden())
if (config->exportDynamic && !isHidden())
return true;
return Flags & WASM_SYMBOL_EXPORTED;
return flags & WASM_SYMBOL_EXPORTED;
}
uint32_t FunctionSymbol::getFunctionIndex() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
return F->Function->getFunctionIndex();
assert(FunctionIndex != INVALID_INDEX);
return FunctionIndex;
if (auto *f = dyn_cast<DefinedFunction>(this))
return f->function->getFunctionIndex();
assert(functionIndex != INVALID_INDEX);
return functionIndex;
}
void FunctionSymbol::setFunctionIndex(uint32_t Index) {
LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
assert(FunctionIndex == INVALID_INDEX);
FunctionIndex = Index;
void FunctionSymbol::setFunctionIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
assert(functionIndex == INVALID_INDEX);
functionIndex = index;
}
bool FunctionSymbol::hasFunctionIndex() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
return F->Function->hasFunctionIndex();
return FunctionIndex != INVALID_INDEX;
if (auto *f = dyn_cast<DefinedFunction>(this))
return f->function->hasFunctionIndex();
return functionIndex != INVALID_INDEX;
}
uint32_t FunctionSymbol::getTableIndex() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
return F->Function->getTableIndex();
assert(TableIndex != INVALID_INDEX);
return TableIndex;
if (auto *f = dyn_cast<DefinedFunction>(this))
return f->function->getTableIndex();
assert(tableIndex != INVALID_INDEX);
return tableIndex;
}
bool FunctionSymbol::hasTableIndex() const {
if (auto *F = dyn_cast<DefinedFunction>(this))
return F->Function->hasTableIndex();
return TableIndex != INVALID_INDEX;
if (auto *f = dyn_cast<DefinedFunction>(this))
return f->function->hasTableIndex();
return tableIndex != INVALID_INDEX;
}
void FunctionSymbol::setTableIndex(uint32_t Index) {
void FunctionSymbol::setTableIndex(uint32_t index) {
// For imports, we set the table index here on the Symbol; for defined
// functions we set the index on the InputFunction so that we don't export
// the same thing twice (keeps the table size down).
if (auto *F = dyn_cast<DefinedFunction>(this)) {
F->Function->setTableIndex(Index);
if (auto *f = dyn_cast<DefinedFunction>(this)) {
f->function->setTableIndex(index);
return;
}
LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
assert(TableIndex == INVALID_INDEX);
TableIndex = Index;
LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
assert(tableIndex == INVALID_INDEX);
tableIndex = index;
}
DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
InputFunction *Function)
: FunctionSymbol(Name, DefinedFunctionKind, Flags, F,
Function ? &Function->Signature : nullptr),
Function(Function) {}
DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
InputFunction *function)
: FunctionSymbol(name, DefinedFunctionKind, flags, f,
function ? &function->signature : nullptr),
function(function) {}
uint32_t DefinedData::getVirtualAddress() const {
LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
if (Segment)
return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset;
return Offset;
if (segment)
return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
return offset;
}
void DefinedData::setVirtualAddress(uint32_t Value) {
LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
assert(!Segment);
Offset = Value;
void DefinedData::setVirtualAddress(uint32_t value) {
LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n");
assert(!segment);
offset = value;
}
uint32_t DefinedData::getOutputSegmentOffset() const {
LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
return Segment->OutputSegmentOffset + Offset;
return segment->outputSegmentOffset + offset;
}
uint32_t DefinedData::getOutputSegmentIndex() const {
LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
return Segment->OutputSeg->Index;
return segment->outputSeg->index;
}
uint32_t GlobalSymbol::getGlobalIndex() const {
if (auto *F = dyn_cast<DefinedGlobal>(this))
return F->Global->getGlobalIndex();
assert(GlobalIndex != INVALID_INDEX);
return GlobalIndex;
if (auto *f = dyn_cast<DefinedGlobal>(this))
return f->global->getGlobalIndex();
assert(globalIndex != INVALID_INDEX);
return globalIndex;
}
void GlobalSymbol::setGlobalIndex(uint32_t Index) {
LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
assert(GlobalIndex == INVALID_INDEX);
GlobalIndex = Index;
void GlobalSymbol::setGlobalIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
assert(globalIndex == INVALID_INDEX);
globalIndex = index;
}
bool GlobalSymbol::hasGlobalIndex() const {
if (auto *F = dyn_cast<DefinedGlobal>(this))
return F->Global->hasGlobalIndex();
return GlobalIndex != INVALID_INDEX;
if (auto *f = dyn_cast<DefinedGlobal>(this))
return f->global->hasGlobalIndex();
return globalIndex != INVALID_INDEX;
}
DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
InputGlobal *Global)
: GlobalSymbol(Name, DefinedGlobalKind, Flags, File,
Global ? &Global->getType() : nullptr),
Global(Global) {}
DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
InputGlobal *global)
: GlobalSymbol(name, DefinedGlobalKind, flags, file,
global ? &global->getType() : nullptr),
global(global) {}
uint32_t EventSymbol::getEventIndex() const {
if (auto *F = dyn_cast<DefinedEvent>(this))
return F->Event->getEventIndex();
assert(EventIndex != INVALID_INDEX);
return EventIndex;
if (auto *f = dyn_cast<DefinedEvent>(this))
return f->event->getEventIndex();
assert(eventIndex != INVALID_INDEX);
return eventIndex;
}
void EventSymbol::setEventIndex(uint32_t Index) {
LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n");
assert(EventIndex == INVALID_INDEX);
EventIndex = Index;
void EventSymbol::setEventIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n");
assert(eventIndex == INVALID_INDEX);
eventIndex = index;
}
bool EventSymbol::hasEventIndex() const {
if (auto *F = dyn_cast<DefinedEvent>(this))
return F->Event->hasEventIndex();
return EventIndex != INVALID_INDEX;
if (auto *f = dyn_cast<DefinedEvent>(this))
return f->event->hasEventIndex();
return eventIndex != INVALID_INDEX;
}
DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
InputEvent *Event)
: EventSymbol(Name, DefinedEventKind, Flags, File,
Event ? &Event->getType() : nullptr,
Event ? &Event->Signature : nullptr),
Event(Event) {}
DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
InputEvent *event)
: EventSymbol(name, DefinedEventKind, flags, file,
event ? &event->getType() : nullptr,
event ? &event->signature : nullptr),
event(event) {}
const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
assert(Section->OutputSec && Section->OutputSec->SectionSym);
return Section->OutputSec->SectionSym;
assert(section->outputSec && section->outputSec->sectionSym);
return section->outputSec->sectionSym;
}
void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
std::string lld::toString(const wasm::Symbol &Sym) {
return lld::maybeDemangleSymbol(Sym.getName());
std::string lld::toString(const wasm::Symbol &sym) {
return lld::maybeDemangleSymbol(sym.getName());
}
std::string lld::maybeDemangleSymbol(StringRef Name) {
if (Config->Demangle)
if (Optional<std::string> S = demangleItanium(Name))
return *S;
return Name;
std::string lld::maybeDemangleSymbol(StringRef name) {
if (config->demangle)
if (Optional<std::string> s = demangleItanium(name))
return *s;
return name;
}
std::string lld::toString(wasm::Symbol::Kind Kind) {
switch (Kind) {
std::string lld::toString(wasm::Symbol::Kind kind) {
switch (kind) {
case wasm::Symbol::DefinedFunctionKind:
return "DefinedFunction";
case wasm::Symbol::DefinedDataKind:
@ -317,24 +317,24 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
}
void lld::wasm::printTraceSymbolUndefined(StringRef Name, const InputFile* File) {
message(toString(File) + ": reference to " + Name);
void lld::wasm::printTraceSymbolUndefined(StringRef name, const InputFile* file) {
message(toString(file) + ": reference to " + name);
}
// Print out a log message for --trace-symbol.
void lld::wasm::printTraceSymbol(Symbol *Sym) {
void lld::wasm::printTraceSymbol(Symbol *sym) {
// Undefined symbols are traced via printTraceSymbolUndefined
if (Sym->isUndefined())
if (sym->isUndefined())
return;
std::string S;
if (Sym->isLazy())
S = ": lazy definition of ";
std::string s;
if (sym->isLazy())
s = ": lazy definition of ";
else
S = ": definition of ";
s = ": definition of ";
message(toString(Sym->getFile()) + S + Sym->getName());
message(toString(sym->getFile()) + s + sym->getName());
}
const char *lld::wasm::DefaultModule = "env";
const char *lld::wasm::FunctionTableName = "__indirect_function_table";
const char *lld::wasm::defaultModule = "env";
const char *lld::wasm::functionTableName = "__indirect_function_table";

View File

@ -20,10 +20,10 @@ namespace wasm {
// Shared string constants
// The default module name to use for symbol imports.
extern const char *DefaultModule;
extern const char *defaultModule;
// The name under which to import or export the wasm table.
extern const char *FunctionTableName;
extern const char *functionTableName;
using llvm::wasm::WasmSymbolType;
@ -54,16 +54,16 @@ public:
LazyKind,
};
Kind kind() const { return SymbolKind; }
Kind kind() const { return symbolKind; }
bool isDefined() const { return !isLazy() && !isUndefined(); }
bool isUndefined() const {
return SymbolKind == UndefinedFunctionKind ||
SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind;
return symbolKind == UndefinedFunctionKind ||
symbolKind == UndefinedDataKind || symbolKind == UndefinedGlobalKind;
}
bool isLazy() const { return SymbolKind == LazyKind; }
bool isLazy() const { return symbolKind == LazyKind; }
bool isLocal() const;
bool isWeak() const;
@ -80,12 +80,12 @@ public:
}
// Returns the symbol name.
StringRef getName() const { return Name; }
StringRef getName() const { return name; }
// Returns the file from which this symbol was created.
InputFile *getFile() const { return File; }
InputFile *getFile() const { return file; }
uint32_t getFlags() const { return Flags; }
uint32_t getFlags() const { return flags; }
InputChunk *getChunk() const;
@ -97,120 +97,120 @@ public:
// final image.
void markLive();
void setHidden(bool IsHidden);
void setHidden(bool isHidden);
// Get/set the index in the output symbol table. This is only used for
// relocatable output.
uint32_t getOutputSymbolIndex() const;
void setOutputSymbolIndex(uint32_t Index);
void setOutputSymbolIndex(uint32_t index);
WasmSymbolType getWasmType() const;
bool isExported() const;
const WasmSignature* getSignature() const;
bool isInGOT() const { return GOTIndex != INVALID_INDEX; }
bool isInGOT() const { return gotIndex != INVALID_INDEX; }
uint32_t getGOTIndex() const {
assert(GOTIndex != INVALID_INDEX);
return GOTIndex;
assert(gotIndex != INVALID_INDEX);
return gotIndex;
}
void setGOTIndex(uint32_t Index);
bool hasGOTIndex() const { return GOTIndex != INVALID_INDEX; }
void setGOTIndex(uint32_t index);
bool hasGOTIndex() const { return gotIndex != INVALID_INDEX; }
protected:
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
: Name(Name), File(F), Flags(Flags), SymbolKind(K),
Referenced(!Config->GcSections), IsUsedInRegularObj(false),
ForceExport(false), CanInline(false), Traced(false) {}
Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
: name(name), file(f), flags(flags), symbolKind(k),
referenced(!config->gcSections), isUsedInRegularObj(false),
forceExport(false), canInline(false), traced(false) {}
StringRef Name;
InputFile *File;
uint32_t Flags;
uint32_t OutputSymbolIndex = INVALID_INDEX;
uint32_t GOTIndex = INVALID_INDEX;
Kind SymbolKind;
StringRef name;
InputFile *file;
uint32_t flags;
uint32_t outputSymbolIndex = INVALID_INDEX;
uint32_t gotIndex = INVALID_INDEX;
Kind symbolKind;
public:
bool Referenced : 1;
bool referenced : 1;
// True if the symbol was used for linking and thus need to be added to the
// output file's symbol table. This is true for all symbols except for
// unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that
// are unreferenced except by other bitcode objects.
bool IsUsedInRegularObj : 1;
bool isUsedInRegularObj : 1;
// True if ths symbol is explicity marked for export (i.e. via the -e/--export
// command line flag)
bool ForceExport : 1;
bool forceExport : 1;
// False if LTO shouldn't inline whatever this symbol points to. If a symbol
// is overwritten after LTO, LTO shouldn't inline the symbol because it
// doesn't know the final contents of the symbol.
bool CanInline : 1;
bool canInline : 1;
// True if this symbol is specified by --trace-symbol option.
bool Traced : 1;
bool traced : 1;
};
class FunctionSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
return S->kind() == DefinedFunctionKind ||
S->kind() == UndefinedFunctionKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedFunctionKind ||
s->kind() == UndefinedFunctionKind;
}
// Get/set the table index
void setTableIndex(uint32_t Index);
void setTableIndex(uint32_t index);
uint32_t getTableIndex() const;
bool hasTableIndex() const;
// Get/set the function index
uint32_t getFunctionIndex() const;
void setFunctionIndex(uint32_t Index);
void setFunctionIndex(uint32_t index);
bool hasFunctionIndex() const;
const WasmSignature *Signature;
const WasmSignature *signature;
protected:
FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
const WasmSignature *Sig)
: Symbol(Name, K, Flags, F), Signature(Sig) {}
FunctionSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
const WasmSignature *sig)
: Symbol(name, k, flags, f), signature(sig) {}
uint32_t TableIndex = INVALID_INDEX;
uint32_t FunctionIndex = INVALID_INDEX;
uint32_t tableIndex = INVALID_INDEX;
uint32_t functionIndex = INVALID_INDEX;
};
class DefinedFunction : public FunctionSymbol {
public:
DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
InputFunction *Function);
DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
InputFunction *function);
static bool classof(const Symbol *S) {
return S->kind() == DefinedFunctionKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedFunctionKind;
}
InputFunction *Function;
InputFunction *function;
};
class UndefinedFunction : public FunctionSymbol {
public:
UndefinedFunction(StringRef Name, StringRef ImportName,
StringRef ImportModule, uint32_t Flags,
InputFile *File = nullptr,
const WasmSignature *Type = nullptr,
bool IsCalledDirectly = true)
: FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type),
ImportName(ImportName), ImportModule(ImportModule), IsCalledDirectly(IsCalledDirectly) {}
UndefinedFunction(StringRef name, StringRef importName,
StringRef importModule, uint32_t flags,
InputFile *file = nullptr,
const WasmSignature *type = nullptr,
bool isCalledDirectly = true)
: FunctionSymbol(name, UndefinedFunctionKind, flags, file, type),
importName(importName), importModule(importModule), isCalledDirectly(isCalledDirectly) {}
static bool classof(const Symbol *S) {
return S->kind() == UndefinedFunctionKind;
static bool classof(const Symbol *s) {
return s->kind() == UndefinedFunctionKind;
}
StringRef ImportName;
StringRef ImportModule;
bool IsCalledDirectly;
StringRef importName;
StringRef importModule;
bool isCalledDirectly;
};
// Section symbols for output sections are different from those for input
@ -218,128 +218,128 @@ public:
// rather than an InputSection.
class OutputSectionSymbol : public Symbol {
public:
OutputSectionSymbol(const OutputSection *S)
OutputSectionSymbol(const OutputSection *s)
: Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL,
nullptr),
Section(S) {}
section(s) {}
static bool classof(const Symbol *S) {
return S->kind() == OutputSectionKind;
static bool classof(const Symbol *s) {
return s->kind() == OutputSectionKind;
}
const OutputSection *Section;
const OutputSection *section;
};
class SectionSymbol : public Symbol {
public:
SectionSymbol(uint32_t Flags, const InputSection *S, InputFile *F = nullptr)
: Symbol("", SectionKind, Flags, F), Section(S) {}
SectionSymbol(uint32_t flags, const InputSection *s, InputFile *f = nullptr)
: Symbol("", SectionKind, flags, f), section(s) {}
static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
static bool classof(const Symbol *s) { return s->kind() == SectionKind; }
const OutputSectionSymbol *getOutputSectionSymbol() const;
const InputSection *Section;
const InputSection *section;
};
class DataSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
return S->kind() == DefinedDataKind || S->kind() == UndefinedDataKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedDataKind || s->kind() == UndefinedDataKind;
}
protected:
DataSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
: Symbol(Name, K, Flags, F) {}
DataSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
: Symbol(name, k, flags, f) {}
};
class DefinedData : public DataSymbol {
public:
// Constructor for regular data symbols originating from input files.
DefinedData(StringRef Name, uint32_t Flags, InputFile *F,
InputSegment *Segment, uint32_t Offset, uint32_t Size)
: DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment),
Offset(Offset), Size(Size) {}
DefinedData(StringRef name, uint32_t flags, InputFile *f,
InputSegment *segment, uint32_t offset, uint32_t size)
: DataSymbol(name, DefinedDataKind, flags, f), segment(segment),
offset(offset), size(size) {}
// Constructor for linker synthetic data symbols.
DefinedData(StringRef Name, uint32_t Flags)
: DataSymbol(Name, DefinedDataKind, Flags, nullptr) {}
DefinedData(StringRef name, uint32_t flags)
: DataSymbol(name, DefinedDataKind, flags, nullptr) {}
static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; }
static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; }
// Returns the output virtual address of a defined data symbol.
uint32_t getVirtualAddress() const;
void setVirtualAddress(uint32_t VA);
void setVirtualAddress(uint32_t va);
// Returns the offset of a defined data symbol within its OutputSegment.
uint32_t getOutputSegmentOffset() const;
uint32_t getOutputSegmentIndex() const;
uint32_t getSize() const { return Size; }
uint32_t getSize() const { return size; }
InputSegment *Segment = nullptr;
InputSegment *segment = nullptr;
protected:
uint32_t Offset = 0;
uint32_t Size = 0;
uint32_t offset = 0;
uint32_t size = 0;
};
class UndefinedData : public DataSymbol {
public:
UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr)
: DataSymbol(Name, UndefinedDataKind, Flags, File) {}
static bool classof(const Symbol *S) {
return S->kind() == UndefinedDataKind;
UndefinedData(StringRef name, uint32_t flags, InputFile *file = nullptr)
: DataSymbol(name, UndefinedDataKind, flags, file) {}
static bool classof(const Symbol *s) {
return s->kind() == UndefinedDataKind;
}
};
class GlobalSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedGlobalKind || s->kind() == UndefinedGlobalKind;
}
const WasmGlobalType *getGlobalType() const { return GlobalType; }
const WasmGlobalType *getGlobalType() const { return globalType; }
// Get/set the global index
uint32_t getGlobalIndex() const;
void setGlobalIndex(uint32_t Index);
void setGlobalIndex(uint32_t index);
bool hasGlobalIndex() const;
protected:
GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
const WasmGlobalType *GlobalType)
: Symbol(Name, K, Flags, F), GlobalType(GlobalType) {}
GlobalSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
const WasmGlobalType *globalType)
: Symbol(name, k, flags, f), globalType(globalType) {}
const WasmGlobalType *GlobalType;
uint32_t GlobalIndex = INVALID_INDEX;
const WasmGlobalType *globalType;
uint32_t globalIndex = INVALID_INDEX;
};
class DefinedGlobal : public GlobalSymbol {
public:
DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
InputGlobal *Global);
DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
InputGlobal *global);
static bool classof(const Symbol *S) {
return S->kind() == DefinedGlobalKind;
static bool classof(const Symbol *s) {
return s->kind() == DefinedGlobalKind;
}
InputGlobal *Global;
InputGlobal *global;
};
class UndefinedGlobal : public GlobalSymbol {
public:
UndefinedGlobal(StringRef Name, StringRef ImportName, StringRef ImportModule,
uint32_t Flags, InputFile *File = nullptr,
const WasmGlobalType *Type = nullptr)
: GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type),
ImportName(ImportName), ImportModule(ImportModule) {}
UndefinedGlobal(StringRef name, StringRef importName, StringRef importModule,
uint32_t flags, InputFile *file = nullptr,
const WasmGlobalType *type = nullptr)
: GlobalSymbol(name, UndefinedGlobalKind, flags, file, type),
importName(importName), importModule(importModule) {}
static bool classof(const Symbol *S) {
return S->kind() == UndefinedGlobalKind;
static bool classof(const Symbol *s) {
return s->kind() == UndefinedGlobalKind;
}
StringRef ImportName;
StringRef ImportModule;
StringRef importName;
StringRef importModule;
};
// Wasm events are features that suspend the current execution and transfer the
@ -356,34 +356,34 @@ public:
// are used, and has name '__cpp_exception' for linking.
class EventSymbol : public Symbol {
public:
static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
static bool classof(const Symbol *s) { return s->kind() == DefinedEventKind; }
const WasmEventType *getEventType() const { return EventType; }
const WasmEventType *getEventType() const { return eventType; }
// Get/set the event index
uint32_t getEventIndex() const;
void setEventIndex(uint32_t Index);
void setEventIndex(uint32_t index);
bool hasEventIndex() const;
const WasmSignature *Signature;
const WasmSignature *signature;
protected:
EventSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
const WasmEventType *EventType, const WasmSignature *Sig)
: Symbol(Name, K, Flags, F), Signature(Sig), EventType(EventType) {}
EventSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
const WasmEventType *eventType, const WasmSignature *sig)
: Symbol(name, k, flags, f), signature(sig), eventType(eventType) {}
const WasmEventType *EventType;
uint32_t EventIndex = INVALID_INDEX;
const WasmEventType *eventType;
uint32_t eventIndex = INVALID_INDEX;
};
class DefinedEvent : public EventSymbol {
public:
DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
InputEvent *Event);
DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
InputEvent *event);
static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
static bool classof(const Symbol *s) { return s->kind() == DefinedEventKind; }
InputEvent *Event;
InputEvent *event;
};
// LazySymbol represents a symbol that is not yet in the link, but we know where
@ -397,11 +397,11 @@ public:
// symbols into consideration.
class LazySymbol : public Symbol {
public:
LazySymbol(StringRef Name, uint32_t Flags, InputFile *File,
const llvm::object::Archive::Symbol &Sym)
: Symbol(Name, LazyKind, Flags, File), ArchiveSymbol(Sym) {}
LazySymbol(StringRef name, uint32_t flags, InputFile *file,
const llvm::object::Archive::Symbol &sym)
: Symbol(name, LazyKind, flags, file), archiveSymbol(sym) {}
static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
void fetch();
// Lazy symbols can have a signature because they can replace an
@ -409,71 +409,71 @@ public:
// signture.
// TODO(sbc): This repetition of the signature field is inelegant. Revisit
// the use of class hierarchy to represent symbol taxonomy.
const WasmSignature *Signature = nullptr;
const WasmSignature *signature = nullptr;
private:
llvm::object::Archive::Symbol ArchiveSymbol;
llvm::object::Archive::Symbol archiveSymbol;
};
// linker-generated symbols
struct WasmSym {
// __global_base
// Symbol marking the start of the global section.
static DefinedData *GlobalBase;
static DefinedData *globalBase;
// __stack_pointer
// Global that holds the address of the top of the explicit value stack in
// linear memory.
static GlobalSymbol *StackPointer;
static GlobalSymbol *stackPointer;
// __data_end
// Symbol marking the end of the data and bss.
static DefinedData *DataEnd;
static DefinedData *dataEnd;
// __heap_base
// Symbol marking the end of the data, bss and explicit stack. Any linear
// memory following this address is not used by the linked code and can
// therefore be used as a backing store for brk()/malloc() implementations.
static DefinedData *HeapBase;
static DefinedData *heapBase;
// __wasm_call_ctors
// Function that directly calls all ctors in priority order.
static DefinedFunction *CallCtors;
static DefinedFunction *callCtors;
// __wasm_init_memory
// Function that initializes passive data segments post-instantiation.
static DefinedFunction *InitMemory;
static DefinedFunction *initMemory;
// __wasm_apply_relocs
// Function that applies relocations to data segment post-instantiation.
static DefinedFunction *ApplyRelocs;
static DefinedFunction *applyRelocs;
// __dso_handle
// Symbol used in calls to __cxa_atexit to determine current DLL
static DefinedData *DsoHandle;
static DefinedData *dsoHandle;
// __table_base
// Used in PIC code for offset of indirect function table
static UndefinedGlobal *TableBase;
static UndefinedGlobal *tableBase;
// __memory_base
// Used in PIC code for offset of global data
static UndefinedGlobal *MemoryBase;
static UndefinedGlobal *memoryBase;
};
// A buffer class that is large enough to hold any Symbol-derived
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
alignas(DefinedData) char B[sizeof(DefinedData)];
alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
alignas(DefinedEvent) char D[sizeof(DefinedEvent)];
alignas(LazySymbol) char E[sizeof(LazySymbol)];
alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)];
alignas(UndefinedData) char G[sizeof(UndefinedData)];
alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)];
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
alignas(DefinedFunction) char a[sizeof(DefinedFunction)];
alignas(DefinedData) char b[sizeof(DefinedData)];
alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)];
alignas(DefinedEvent) char d[sizeof(DefinedEvent)];
alignas(LazySymbol) char e[sizeof(LazySymbol)];
alignas(UndefinedFunction) char f[sizeof(UndefinedFunction)];
alignas(UndefinedData) char g[sizeof(UndefinedData)];
alignas(UndefinedGlobal) char h[sizeof(UndefinedGlobal)];
alignas(SectionSymbol) char i[sizeof(SectionSymbol)];
};
// It is important to keep the size of SymbolUnion small for performance and
@ -481,11 +481,11 @@ union SymbolUnion {
// UndefinedFunction on a 64-bit system.
static_assert(sizeof(SymbolUnion) <= 96, "SymbolUnion too large");
void printTraceSymbol(Symbol *Sym);
void printTraceSymbolUndefined(StringRef Name, const InputFile* File);
void printTraceSymbol(Symbol *sym);
void printTraceSymbolUndefined(StringRef name, const InputFile* file);
template <typename T, typename... ArgT>
T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
T *replaceSymbol(Symbol *s, ArgT &&... arg) {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
@ -494,28 +494,28 @@ T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
Symbol SymCopy = *S;
Symbol symCopy = *s;
T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
S2->ForceExport = SymCopy.ForceExport;
S2->CanInline = SymCopy.CanInline;
S2->Traced = SymCopy.Traced;
T *s2 = new (s) T(std::forward<ArgT>(arg)...);
s2->isUsedInRegularObj = symCopy.isUsedInRegularObj;
s2->forceExport = symCopy.forceExport;
s2->canInline = symCopy.canInline;
s2->traced = symCopy.traced;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
if (S2->Traced)
printTraceSymbol(S2);
if (s2->traced)
printTraceSymbol(s2);
return S2;
return s2;
}
} // namespace wasm
// Returns a symbol name for an error message.
std::string toString(const wasm::Symbol &Sym);
std::string toString(wasm::Symbol::Kind Kind);
std::string maybeDemangleSymbol(StringRef Name);
std::string toString(const wasm::Symbol &sym);
std::string toString(wasm::Symbol::Kind kind);
std::string maybeDemangleSymbol(StringRef name);
} // namespace lld

View File

@ -25,7 +25,7 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
OutStruct lld::wasm::Out;
OutStruct lld::wasm::out;
namespace {
@ -36,512 +36,512 @@ namespace {
// of the parent section.
class SubSection {
public:
explicit SubSection(uint32_t Type) : Type(Type) {}
explicit SubSection(uint32_t type) : type(type) {}
void writeTo(raw_ostream &To) {
OS.flush();
writeUleb128(To, Type, "subsection type");
writeUleb128(To, Body.size(), "subsection size");
To.write(Body.data(), Body.size());
void writeTo(raw_ostream &to) {
os.flush();
writeUleb128(to, type, "subsection type");
writeUleb128(to, body.size(), "subsection size");
to.write(body.data(), body.size());
}
private:
uint32_t Type;
std::string Body;
uint32_t type;
std::string body;
public:
raw_string_ostream OS{Body};
raw_string_ostream os{body};
};
} // namespace
void DylinkSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, MemSize, "MemSize");
writeUleb128(OS, MemAlign, "MemAlign");
writeUleb128(OS, Out.ElemSec->numEntries(), "TableSize");
writeUleb128(OS, 0, "TableAlign");
writeUleb128(OS, Symtab->SharedFiles.size(), "Needed");
for (auto *SO : Symtab->SharedFiles)
writeStr(OS, llvm::sys::path::filename(SO->getName()), "so name");
writeUleb128(os, memSize, "MemSize");
writeUleb128(os, memAlign, "MemAlign");
writeUleb128(os, out.elemSec->numEntries(), "TableSize");
writeUleb128(os, 0, "TableAlign");
writeUleb128(os, symtab->sharedFiles.size(), "Needed");
for (auto *so : symtab->sharedFiles)
writeStr(os, llvm::sys::path::filename(so->getName()), "so name");
}
uint32_t TypeSection::registerType(const WasmSignature &Sig) {
auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
if (Pair.second) {
LLVM_DEBUG(llvm::dbgs() << "type " << toString(Sig) << "\n");
Types.push_back(&Sig);
uint32_t TypeSection::registerType(const WasmSignature &sig) {
auto pair = typeIndices.insert(std::make_pair(sig, types.size()));
if (pair.second) {
LLVM_DEBUG(llvm::dbgs() << "type " << toString(sig) << "\n");
types.push_back(&sig);
}
return Pair.first->second;
return pair.first->second;
}
uint32_t TypeSection::lookupType(const WasmSignature &Sig) {
auto It = TypeIndices.find(Sig);
if (It == TypeIndices.end()) {
error("type not found: " + toString(Sig));
uint32_t TypeSection::lookupType(const WasmSignature &sig) {
auto it = typeIndices.find(sig);
if (it == typeIndices.end()) {
error("type not found: " + toString(sig));
return 0;
}
return It->second;
return it->second;
}
void TypeSection::writeBody() {
writeUleb128(BodyOutputStream, Types.size(), "type count");
for (const WasmSignature *Sig : Types)
writeSig(BodyOutputStream, *Sig);
writeUleb128(bodyOutputStream, types.size(), "type count");
for (const WasmSignature *sig : types)
writeSig(bodyOutputStream, *sig);
}
uint32_t ImportSection::getNumImports() const {
assert(IsSealed);
uint32_t NumImports = ImportedSymbols.size() + GOTSymbols.size();
if (Config->ImportMemory)
++NumImports;
if (Config->ImportTable)
++NumImports;
return NumImports;
assert(isSealed);
uint32_t numImports = importedSymbols.size() + gotSymbols.size();
if (config->importMemory)
++numImports;
if (config->importTable)
++numImports;
return numImports;
}
void ImportSection::addGOTEntry(Symbol *Sym) {
assert(!IsSealed);
if (Sym->hasGOTIndex())
void ImportSection::addGOTEntry(Symbol *sym) {
assert(!isSealed);
if (sym->hasGOTIndex())
return;
Sym->setGOTIndex(NumImportedGlobals++);
GOTSymbols.push_back(Sym);
sym->setGOTIndex(numImportedGlobals++);
gotSymbols.push_back(sym);
}
void ImportSection::addImport(Symbol *Sym) {
assert(!IsSealed);
ImportedSymbols.emplace_back(Sym);
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
F->setFunctionIndex(NumImportedFunctions++);
else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
G->setGlobalIndex(NumImportedGlobals++);
void ImportSection::addImport(Symbol *sym) {
assert(!isSealed);
importedSymbols.emplace_back(sym);
if (auto *f = dyn_cast<FunctionSymbol>(sym))
f->setFunctionIndex(numImportedFunctions++);
else if (auto *g = dyn_cast<GlobalSymbol>(sym))
g->setGlobalIndex(numImportedGlobals++);
else
cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
cast<EventSymbol>(sym)->setEventIndex(numImportedEvents++);
}
void ImportSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, getNumImports(), "import count");
writeUleb128(os, getNumImports(), "import count");
if (Config->ImportMemory) {
WasmImport Import;
Import.Module = DefaultModule;
Import.Field = "memory";
Import.Kind = WASM_EXTERNAL_MEMORY;
Import.Memory.Flags = 0;
Import.Memory.Initial = Out.MemorySec->NumMemoryPages;
if (Out.MemorySec->MaxMemoryPages != 0 || Config->SharedMemory) {
Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
Import.Memory.Maximum = Out.MemorySec->MaxMemoryPages;
if (config->importMemory) {
WasmImport import;
import.Module = defaultModule;
import.Field = "memory";
import.Kind = WASM_EXTERNAL_MEMORY;
import.Memory.Flags = 0;
import.Memory.Initial = out.memorySec->numMemoryPages;
if (out.memorySec->maxMemoryPages != 0 || config->sharedMemory) {
import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
import.Memory.Maximum = out.memorySec->maxMemoryPages;
}
if (Config->SharedMemory)
Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
writeImport(OS, Import);
if (config->sharedMemory)
import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
writeImport(os, import);
}
if (Config->ImportTable) {
uint32_t TableSize = Out.ElemSec->ElemOffset + Out.ElemSec->numEntries();
WasmImport Import;
Import.Module = DefaultModule;
Import.Field = FunctionTableName;
Import.Kind = WASM_EXTERNAL_TABLE;
Import.Table.ElemType = WASM_TYPE_FUNCREF;
Import.Table.Limits = {0, TableSize, 0};
writeImport(OS, Import);
if (config->importTable) {
uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries();
WasmImport import;
import.Module = defaultModule;
import.Field = functionTableName;
import.Kind = WASM_EXTERNAL_TABLE;
import.Table.ElemType = WASM_TYPE_FUNCREF;
import.Table.Limits = {0, tableSize, 0};
writeImport(os, import);
}
for (const Symbol *Sym : ImportedSymbols) {
WasmImport Import;
if (auto *F = dyn_cast<UndefinedFunction>(Sym)) {
Import.Field = F->ImportName;
Import.Module = F->ImportModule;
} else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) {
Import.Field = G->ImportName;
Import.Module = G->ImportModule;
for (const Symbol *sym : importedSymbols) {
WasmImport import;
if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
import.Field = f->importName;
import.Module = f->importModule;
} else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) {
import.Field = g->importName;
import.Module = g->importModule;
} else {
Import.Field = Sym->getName();
Import.Module = DefaultModule;
import.Field = sym->getName();
import.Module = defaultModule;
}
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
Import.Kind = WASM_EXTERNAL_FUNCTION;
Import.SigIndex = Out.TypeSec->lookupType(*FunctionSym->Signature);
} else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
Import.Kind = WASM_EXTERNAL_GLOBAL;
Import.Global = *GlobalSym->getGlobalType();
if (auto *functionSym = dyn_cast<FunctionSymbol>(sym)) {
import.Kind = WASM_EXTERNAL_FUNCTION;
import.SigIndex = out.typeSec->lookupType(*functionSym->signature);
} else if (auto *globalSym = dyn_cast<GlobalSymbol>(sym)) {
import.Kind = WASM_EXTERNAL_GLOBAL;
import.Global = *globalSym->getGlobalType();
} else {
auto *EventSym = cast<EventSymbol>(Sym);
Import.Kind = WASM_EXTERNAL_EVENT;
Import.Event.Attribute = EventSym->getEventType()->Attribute;
Import.Event.SigIndex = Out.TypeSec->lookupType(*EventSym->Signature);
auto *eventSym = cast<EventSymbol>(sym);
import.Kind = WASM_EXTERNAL_EVENT;
import.Event.Attribute = eventSym->getEventType()->Attribute;
import.Event.SigIndex = out.typeSec->lookupType(*eventSym->signature);
}
writeImport(OS, Import);
writeImport(os, import);
}
for (const Symbol *Sym : GOTSymbols) {
WasmImport Import;
Import.Kind = WASM_EXTERNAL_GLOBAL;
Import.Global = {WASM_TYPE_I32, true};
if (isa<DataSymbol>(Sym))
Import.Module = "GOT.mem";
for (const Symbol *sym : gotSymbols) {
WasmImport import;
import.Kind = WASM_EXTERNAL_GLOBAL;
import.Global = {WASM_TYPE_I32, true};
if (isa<DataSymbol>(sym))
import.Module = "GOT.mem";
else
Import.Module = "GOT.func";
Import.Field = Sym->getName();
writeImport(OS, Import);
import.Module = "GOT.func";
import.Field = sym->getName();
writeImport(os, import);
}
}
void FunctionSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, InputFunctions.size(), "function count");
for (const InputFunction *Func : InputFunctions)
writeUleb128(OS, Out.TypeSec->lookupType(Func->Signature), "sig index");
writeUleb128(os, inputFunctions.size(), "function count");
for (const InputFunction *func : inputFunctions)
writeUleb128(os, out.typeSec->lookupType(func->signature), "sig index");
}
void FunctionSection::addFunction(InputFunction *Func) {
if (!Func->Live)
void FunctionSection::addFunction(InputFunction *func) {
if (!func->live)
return;
uint32_t FunctionIndex =
Out.ImportSec->getNumImportedFunctions() + InputFunctions.size();
InputFunctions.emplace_back(Func);
Func->setFunctionIndex(FunctionIndex);
uint32_t functionIndex =
out.importSec->getNumImportedFunctions() + inputFunctions.size();
inputFunctions.emplace_back(func);
func->setFunctionIndex(functionIndex);
}
void TableSection::writeBody() {
uint32_t TableSize = Out.ElemSec->ElemOffset + Out.ElemSec->numEntries();
uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries();
raw_ostream &OS = BodyOutputStream;
writeUleb128(OS, 1, "table count");
WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits});
raw_ostream &os = bodyOutputStream;
writeUleb128(os, 1, "table count");
WasmLimits limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
writeTableType(os, WasmTable{WASM_TYPE_FUNCREF, limits});
}
void MemorySection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
bool HasMax = MaxMemoryPages != 0 || Config->SharedMemory;
writeUleb128(OS, 1, "memory count");
unsigned Flags = 0;
if (HasMax)
Flags |= WASM_LIMITS_FLAG_HAS_MAX;
if (Config->SharedMemory)
Flags |= WASM_LIMITS_FLAG_IS_SHARED;
writeUleb128(OS, Flags, "memory limits flags");
writeUleb128(OS, NumMemoryPages, "initial pages");
if (HasMax)
writeUleb128(OS, MaxMemoryPages, "max pages");
bool hasMax = maxMemoryPages != 0 || config->sharedMemory;
writeUleb128(os, 1, "memory count");
unsigned flags = 0;
if (hasMax)
flags |= WASM_LIMITS_FLAG_HAS_MAX;
if (config->sharedMemory)
flags |= WASM_LIMITS_FLAG_IS_SHARED;
writeUleb128(os, flags, "memory limits flags");
writeUleb128(os, numMemoryPages, "initial pages");
if (hasMax)
writeUleb128(os, maxMemoryPages, "max pages");
}
void GlobalSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, numGlobals(), "global count");
for (const InputGlobal *G : InputGlobals)
writeGlobal(OS, G->Global);
for (const DefinedData *Sym : DefinedFakeGlobals) {
WasmGlobal Global;
Global.Type = {WASM_TYPE_I32, false};
Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
writeGlobal(OS, Global);
writeUleb128(os, numGlobals(), "global count");
for (const InputGlobal *g : inputGlobals)
writeGlobal(os, g->global);
for (const DefinedData *sym : definedFakeGlobals) {
WasmGlobal global;
global.Type = {WASM_TYPE_I32, false};
global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
global.InitExpr.Value.Int32 = sym->getVirtualAddress();
writeGlobal(os, global);
}
}
void GlobalSection::addGlobal(InputGlobal *Global) {
if (!Global->Live)
void GlobalSection::addGlobal(InputGlobal *global) {
if (!global->live)
return;
uint32_t GlobalIndex =
Out.ImportSec->getNumImportedGlobals() + InputGlobals.size();
LLVM_DEBUG(dbgs() << "addGlobal: " << GlobalIndex << "\n");
Global->setGlobalIndex(GlobalIndex);
Out.GlobalSec->InputGlobals.push_back(Global);
uint32_t globalIndex =
out.importSec->getNumImportedGlobals() + inputGlobals.size();
LLVM_DEBUG(dbgs() << "addGlobal: " << globalIndex << "\n");
global->setGlobalIndex(globalIndex);
out.globalSec->inputGlobals.push_back(global);
}
void EventSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, InputEvents.size(), "event count");
for (InputEvent *E : InputEvents) {
E->Event.Type.SigIndex = Out.TypeSec->lookupType(E->Signature);
writeEvent(OS, E->Event);
writeUleb128(os, inputEvents.size(), "event count");
for (InputEvent *e : inputEvents) {
e->event.Type.SigIndex = out.typeSec->lookupType(e->signature);
writeEvent(os, e->event);
}
}
void EventSection::addEvent(InputEvent *Event) {
if (!Event->Live)
void EventSection::addEvent(InputEvent *event) {
if (!event->live)
return;
uint32_t EventIndex =
Out.ImportSec->getNumImportedEvents() + InputEvents.size();
LLVM_DEBUG(dbgs() << "addEvent: " << EventIndex << "\n");
Event->setEventIndex(EventIndex);
InputEvents.push_back(Event);
uint32_t eventIndex =
out.importSec->getNumImportedEvents() + inputEvents.size();
LLVM_DEBUG(dbgs() << "addEvent: " << eventIndex << "\n");
event->setEventIndex(eventIndex);
inputEvents.push_back(event);
}
void ExportSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, Exports.size(), "export count");
for (const WasmExport &Export : Exports)
writeExport(OS, Export);
writeUleb128(os, exports.size(), "export count");
for (const WasmExport &export_ : exports)
writeExport(os, export_);
}
void ElemSection::addEntry(FunctionSymbol *Sym) {
if (Sym->hasTableIndex())
void ElemSection::addEntry(FunctionSymbol *sym) {
if (sym->hasTableIndex())
return;
Sym->setTableIndex(ElemOffset + IndirectFunctions.size());
IndirectFunctions.emplace_back(Sym);
sym->setTableIndex(elemOffset + indirectFunctions.size());
indirectFunctions.emplace_back(sym);
}
void ElemSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, 1, "segment count");
writeUleb128(OS, 0, "table index");
WasmInitExpr InitExpr;
if (Config->Pic) {
InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex();
writeUleb128(os, 1, "segment count");
writeUleb128(os, 0, "table index");
WasmInitExpr initExpr;
if (config->isPic) {
initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
initExpr.Value.Global = WasmSym::tableBase->getGlobalIndex();
} else {
InitExpr.Opcode = WASM_OPCODE_I32_CONST;
InitExpr.Value.Int32 = ElemOffset;
initExpr.Opcode = WASM_OPCODE_I32_CONST;
initExpr.Value.Int32 = elemOffset;
}
writeInitExpr(OS, InitExpr);
writeUleb128(OS, IndirectFunctions.size(), "elem count");
writeInitExpr(os, initExpr);
writeUleb128(os, indirectFunctions.size(), "elem count");
uint32_t TableIndex = ElemOffset;
for (const FunctionSymbol *Sym : IndirectFunctions) {
assert(Sym->getTableIndex() == TableIndex);
writeUleb128(OS, Sym->getFunctionIndex(), "function index");
++TableIndex;
uint32_t tableIndex = elemOffset;
for (const FunctionSymbol *sym : indirectFunctions) {
assert(sym->getTableIndex() == tableIndex);
writeUleb128(os, sym->getFunctionIndex(), "function index");
++tableIndex;
}
}
void DataCountSection::writeBody() {
writeUleb128(BodyOutputStream, NumSegments, "data count");
writeUleb128(bodyOutputStream, numSegments, "data count");
}
bool DataCountSection::isNeeded() const {
return NumSegments && Config->PassiveSegments;
return numSegments && config->passiveSegments;
}
static uint32_t getWasmFlags(const Symbol *Sym) {
uint32_t Flags = 0;
if (Sym->isLocal())
Flags |= WASM_SYMBOL_BINDING_LOCAL;
if (Sym->isWeak())
Flags |= WASM_SYMBOL_BINDING_WEAK;
if (Sym->isHidden())
Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
if (Sym->isUndefined())
Flags |= WASM_SYMBOL_UNDEFINED;
if (auto *F = dyn_cast<UndefinedFunction>(Sym)) {
if (F->getName() != F->ImportName)
Flags |= WASM_SYMBOL_EXPLICIT_NAME;
} else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) {
if (G->getName() != G->ImportName)
Flags |= WASM_SYMBOL_EXPLICIT_NAME;
static uint32_t getWasmFlags(const Symbol *sym) {
uint32_t flags = 0;
if (sym->isLocal())
flags |= WASM_SYMBOL_BINDING_LOCAL;
if (sym->isWeak())
flags |= WASM_SYMBOL_BINDING_WEAK;
if (sym->isHidden())
flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
if (sym->isUndefined())
flags |= WASM_SYMBOL_UNDEFINED;
if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
if (f->getName() != f->importName)
flags |= WASM_SYMBOL_EXPLICIT_NAME;
} else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) {
if (g->getName() != g->importName)
flags |= WASM_SYMBOL_EXPLICIT_NAME;
}
return Flags;
return flags;
}
void LinkingSection::writeBody() {
raw_ostream &OS = BodyOutputStream;
raw_ostream &os = bodyOutputStream;
writeUleb128(OS, WasmMetadataVersion, "Version");
writeUleb128(os, WasmMetadataVersion, "Version");
if (!SymtabEntries.empty()) {
SubSection Sub(WASM_SYMBOL_TABLE);
writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols");
if (!symtabEntries.empty()) {
SubSection sub(WASM_SYMBOL_TABLE);
writeUleb128(sub.os, symtabEntries.size(), "num symbols");
for (const Symbol *Sym : SymtabEntries) {
assert(Sym->isDefined() || Sym->isUndefined());
WasmSymbolType Kind = Sym->getWasmType();
uint32_t Flags = getWasmFlags(Sym);
for (const Symbol *sym : symtabEntries) {
assert(sym->isDefined() || sym->isUndefined());
WasmSymbolType kind = sym->getWasmType();
uint32_t flags = getWasmFlags(sym);
writeU8(Sub.OS, Kind, "sym kind");
writeUleb128(Sub.OS, Flags, "sym flags");
writeU8(sub.os, kind, "sym kind");
writeUleb128(sub.os, flags, "sym flags");
if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
writeUleb128(Sub.OS, F->getFunctionIndex(), "index");
if (Sym->isDefined() || (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(Sub.OS, Sym->getName(), "sym name");
} else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
if (Sym->isDefined() || (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(Sub.OS, Sym->getName(), "sym name");
} else if (auto *E = dyn_cast<EventSymbol>(Sym)) {
writeUleb128(Sub.OS, E->getEventIndex(), "index");
if (Sym->isDefined() || (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(Sub.OS, Sym->getName(), "sym name");
} else if (isa<DataSymbol>(Sym)) {
writeStr(Sub.OS, Sym->getName(), "sym name");
if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(),
if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
writeUleb128(sub.os, f->getFunctionIndex(), "index");
if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(sub.os, sym->getName(), "sym name");
} else if (auto *g = dyn_cast<GlobalSymbol>(sym)) {
writeUleb128(sub.os, g->getGlobalIndex(), "index");
if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(sub.os, sym->getName(), "sym name");
} else if (auto *e = dyn_cast<EventSymbol>(sym)) {
writeUleb128(sub.os, e->getEventIndex(), "index");
if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(sub.os, sym->getName(), "sym name");
} else if (isa<DataSymbol>(sym)) {
writeStr(sub.os, sym->getName(), "sym name");
if (auto *dataSym = dyn_cast<DefinedData>(sym)) {
writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index");
writeUleb128(sub.os, dataSym->getOutputSegmentOffset(),
"data offset");
writeUleb128(Sub.OS, DataSym->getSize(), "data size");
writeUleb128(sub.os, dataSym->getSize(), "data size");
}
} else {
auto *S = cast<OutputSectionSymbol>(Sym);
writeUleb128(Sub.OS, S->Section->SectionIndex, "sym section index");
auto *s = cast<OutputSectionSymbol>(sym);
writeUleb128(sub.os, s->section->sectionIndex, "sym section index");
}
}
Sub.writeTo(OS);
sub.writeTo(os);
}
if (DataSegments.size()) {
SubSection Sub(WASM_SEGMENT_INFO);
writeUleb128(Sub.OS, DataSegments.size(), "num data segments");
for (const OutputSegment *S : DataSegments) {
writeStr(Sub.OS, S->Name, "segment name");
writeUleb128(Sub.OS, S->Alignment, "alignment");
writeUleb128(Sub.OS, 0, "flags");
if (dataSegments.size()) {
SubSection sub(WASM_SEGMENT_INFO);
writeUleb128(sub.os, dataSegments.size(), "num data segments");
for (const OutputSegment *s : dataSegments) {
writeStr(sub.os, s->name, "segment name");
writeUleb128(sub.os, s->alignment, "alignment");
writeUleb128(sub.os, 0, "flags");
}
Sub.writeTo(OS);
sub.writeTo(os);
}
if (!InitFunctions.empty()) {
SubSection Sub(WASM_INIT_FUNCS);
writeUleb128(Sub.OS, InitFunctions.size(), "num init functions");
for (const WasmInitEntry &F : InitFunctions) {
writeUleb128(Sub.OS, F.Priority, "priority");
writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index");
if (!initFunctions.empty()) {
SubSection sub(WASM_INIT_FUNCS);
writeUleb128(sub.os, initFunctions.size(), "num init functions");
for (const WasmInitEntry &f : initFunctions) {
writeUleb128(sub.os, f.priority, "priority");
writeUleb128(sub.os, f.sym->getOutputSymbolIndex(), "function index");
}
Sub.writeTo(OS);
sub.writeTo(os);
}
struct ComdatEntry {
unsigned Kind;
uint32_t Index;
unsigned kind;
uint32_t index;
};
std::map<StringRef, std::vector<ComdatEntry>> Comdats;
std::map<StringRef, std::vector<ComdatEntry>> comdats;
for (const InputFunction *F : Out.FunctionSec->InputFunctions) {
StringRef Comdat = F->getComdatName();
if (!Comdat.empty())
Comdats[Comdat].emplace_back(
ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
for (const InputFunction *f : out.functionSec->inputFunctions) {
StringRef comdat = f->getComdatName();
if (!comdat.empty())
comdats[comdat].emplace_back(
ComdatEntry{WASM_COMDAT_FUNCTION, f->getFunctionIndex()});
}
for (uint32_t I = 0; I < DataSegments.size(); ++I) {
const auto &InputSegments = DataSegments[I]->InputSegments;
if (InputSegments.empty())
for (uint32_t i = 0; i < dataSegments.size(); ++i) {
const auto &inputSegments = dataSegments[i]->inputSegments;
if (inputSegments.empty())
continue;
StringRef Comdat = InputSegments[0]->getComdatName();
StringRef comdat = inputSegments[0]->getComdatName();
#ifndef NDEBUG
for (const InputSegment *IS : InputSegments)
assert(IS->getComdatName() == Comdat);
for (const InputSegment *isec : inputSegments)
assert(isec->getComdatName() == comdat);
#endif
if (!Comdat.empty())
Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
if (!comdat.empty())
comdats[comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, i});
}
if (!Comdats.empty()) {
SubSection Sub(WASM_COMDAT_INFO);
writeUleb128(Sub.OS, Comdats.size(), "num comdats");
for (const auto &C : Comdats) {
writeStr(Sub.OS, C.first, "comdat name");
writeUleb128(Sub.OS, 0, "comdat flags"); // flags for future use
writeUleb128(Sub.OS, C.second.size(), "num entries");
for (const ComdatEntry &Entry : C.second) {
writeU8(Sub.OS, Entry.Kind, "entry kind");
writeUleb128(Sub.OS, Entry.Index, "entry index");
if (!comdats.empty()) {
SubSection sub(WASM_COMDAT_INFO);
writeUleb128(sub.os, comdats.size(), "num comdats");
for (const auto &c : comdats) {
writeStr(sub.os, c.first, "comdat name");
writeUleb128(sub.os, 0, "comdat flags"); // flags for future use
writeUleb128(sub.os, c.second.size(), "num entries");
for (const ComdatEntry &entry : c.second) {
writeU8(sub.os, entry.kind, "entry kind");
writeUleb128(sub.os, entry.index, "entry index");
}
}
Sub.writeTo(OS);
sub.writeTo(os);
}
}
void LinkingSection::addToSymtab(Symbol *Sym) {
Sym->setOutputSymbolIndex(SymtabEntries.size());
SymtabEntries.emplace_back(Sym);
void LinkingSection::addToSymtab(Symbol *sym) {
sym->setOutputSymbolIndex(symtabEntries.size());
symtabEntries.emplace_back(sym);
}
unsigned NameSection::numNames() const {
unsigned NumNames = Out.ImportSec->getNumImportedFunctions();
for (const InputFunction *F : Out.FunctionSec->InputFunctions)
if (!F->getName().empty() || !F->getDebugName().empty())
++NumNames;
unsigned numNames = out.importSec->getNumImportedFunctions();
for (const InputFunction *f : out.functionSec->inputFunctions)
if (!f->getName().empty() || !f->getDebugName().empty())
++numNames;
return NumNames;
return numNames;
}
// Create the custom "name" section containing debug symbol names.
void NameSection::writeBody() {
SubSection Sub(WASM_NAMES_FUNCTION);
writeUleb128(Sub.OS, numNames(), "name count");
SubSection sub(WASM_NAMES_FUNCTION);
writeUleb128(sub.os, numNames(), "name count");
// Names must appear in function index order. As it happens ImportedSymbols
// and InputFunctions are numbered in order with imported functions coming
// first.
for (const Symbol *S : Out.ImportSec->ImportedSymbols) {
if (auto *F = dyn_cast<FunctionSymbol>(S)) {
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
writeStr(Sub.OS, toString(*S), "symbol name");
for (const Symbol *s : out.importSec->importedSymbols) {
if (auto *f = dyn_cast<FunctionSymbol>(s)) {
writeUleb128(sub.os, f->getFunctionIndex(), "func index");
writeStr(sub.os, toString(*s), "symbol name");
}
}
for (const InputFunction *F : Out.FunctionSec->InputFunctions) {
if (!F->getName().empty()) {
writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
if (!F->getDebugName().empty()) {
writeStr(Sub.OS, F->getDebugName(), "symbol name");
for (const InputFunction *f : out.functionSec->inputFunctions) {
if (!f->getName().empty()) {
writeUleb128(sub.os, f->getFunctionIndex(), "func index");
if (!f->getDebugName().empty()) {
writeStr(sub.os, f->getDebugName(), "symbol name");
} else {
writeStr(Sub.OS, maybeDemangleSymbol(F->getName()), "symbol name");
writeStr(sub.os, maybeDemangleSymbol(f->getName()), "symbol name");
}
}
}
Sub.writeTo(BodyOutputStream);
sub.writeTo(bodyOutputStream);
}
void ProducersSection::addInfo(const WasmProducerInfo &Info) {
for (auto &Producers :
{std::make_pair(&Info.Languages, &Languages),
std::make_pair(&Info.Tools, &Tools), std::make_pair(&Info.SDKs, &SDKs)})
for (auto &Producer : *Producers.first)
if (Producers.second->end() ==
llvm::find_if(*Producers.second,
[&](std::pair<std::string, std::string> Seen) {
return Seen.first == Producer.first;
void ProducersSection::addInfo(const WasmProducerInfo &info) {
for (auto &producers :
{std::make_pair(&info.Languages, &languages),
std::make_pair(&info.Tools, &tools), std::make_pair(&info.SDKs, &sDKs)})
for (auto &producer : *producers.first)
if (producers.second->end() ==
llvm::find_if(*producers.second,
[&](std::pair<std::string, std::string> seen) {
return seen.first == producer.first;
}))
Producers.second->push_back(Producer);
producers.second->push_back(producer);
}
void ProducersSection::writeBody() {
auto &OS = BodyOutputStream;
writeUleb128(OS, fieldCount(), "field count");
for (auto &Field :
{std::make_pair("language", Languages),
std::make_pair("processed-by", Tools), std::make_pair("sdk", SDKs)}) {
if (Field.second.empty())
auto &os = bodyOutputStream;
writeUleb128(os, fieldCount(), "field count");
for (auto &field :
{std::make_pair("language", languages),
std::make_pair("processed-by", tools), std::make_pair("sdk", sDKs)}) {
if (field.second.empty())
continue;
writeStr(OS, Field.first, "field name");
writeUleb128(OS, Field.second.size(), "number of entries");
for (auto &Entry : Field.second) {
writeStr(OS, Entry.first, "producer name");
writeStr(OS, Entry.second, "producer version");
writeStr(os, field.first, "field name");
writeUleb128(os, field.second.size(), "number of entries");
for (auto &entry : field.second) {
writeStr(os, entry.first, "producer name");
writeStr(os, entry.second, "producer version");
}
}
}
void TargetFeaturesSection::writeBody() {
SmallVector<std::string, 8> Emitted(Features.begin(), Features.end());
llvm::sort(Emitted);
auto &OS = BodyOutputStream;
writeUleb128(OS, Emitted.size(), "feature count");
for (auto &Feature : Emitted) {
writeU8(OS, WASM_FEATURE_PREFIX_USED, "feature used prefix");
writeStr(OS, Feature, "feature name");
SmallVector<std::string, 8> emitted(features.begin(), features.end());
llvm::sort(emitted);
auto &os = bodyOutputStream;
writeUleb128(os, emitted.size(), "feature count");
for (auto &feature : emitted) {
writeU8(os, WASM_FEATURE_PREFIX_USED, "feature used prefix");
writeStr(os, feature, "feature name");
}
}
void RelocSection::writeBody() {
uint32_t Count = Sec->getNumRelocations();
assert(Sec->SectionIndex != UINT32_MAX);
writeUleb128(BodyOutputStream, Sec->SectionIndex, "reloc section");
writeUleb128(BodyOutputStream, Count, "reloc count");
Sec->writeRelocations(BodyOutputStream);
uint32_t count = sec->getNumRelocations();
assert(sec->sectionIndex != UINT32_MAX);
writeUleb128(bodyOutputStream, sec->sectionIndex, "reloc section");
writeUleb128(bodyOutputStream, count, "reloc count");
sec->writeRelocations(bodyOutputStream);
}

View File

@ -29,41 +29,41 @@ namespace wasm {
// An init entry to be written to either the synthetic init func or the
// linking metadata.
struct WasmInitEntry {
const FunctionSymbol *Sym;
uint32_t Priority;
const FunctionSymbol *sym;
uint32_t priority;
};
class SyntheticSection : public OutputSection {
public:
SyntheticSection(uint32_t Type, std::string Name = "")
: OutputSection(Type, Name), BodyOutputStream(Body) {
if (!Name.empty())
writeStr(BodyOutputStream, Name, "section name");
SyntheticSection(uint32_t type, std::string name = "")
: OutputSection(type, name), bodyOutputStream(body) {
if (!name.empty())
writeStr(bodyOutputStream, name, "section name");
}
void writeTo(uint8_t *Buf) override {
assert(Offset);
void writeTo(uint8_t *buf) override {
assert(offset);
log("writing " + toString(*this));
memcpy(Buf + Offset, Header.data(), Header.size());
memcpy(Buf + Offset + Header.size(), Body.data(), Body.size());
memcpy(buf + offset, header.data(), header.size());
memcpy(buf + offset + header.size(), body.data(), body.size());
}
size_t getSize() const override { return Header.size() + Body.size(); }
size_t getSize() const override { return header.size() + body.size(); }
virtual void writeBody() {}
void finalizeContents() override {
writeBody();
BodyOutputStream.flush();
createHeader(Body.size());
bodyOutputStream.flush();
createHeader(body.size());
}
raw_ostream &getStream() { return BodyOutputStream; }
raw_ostream &getStream() { return bodyOutputStream; }
std::string Body;
std::string body;
protected:
llvm::raw_string_ostream BodyOutputStream;
llvm::raw_string_ostream bodyOutputStream;
};
// Create the custom "dylink" section containing information for the dynamic
@ -73,25 +73,25 @@ protected:
class DylinkSection : public SyntheticSection {
public:
DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink") {}
bool isNeeded() const override { return Config->Pic; }
bool isNeeded() const override { return config->isPic; }
void writeBody() override;
uint32_t MemAlign = 0;
uint32_t MemSize = 0;
uint32_t memAlign = 0;
uint32_t memSize = 0;
};
class TypeSection : public SyntheticSection {
public:
TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {}
bool isNeeded() const override { return Types.size() > 0; };
bool isNeeded() const override { return types.size() > 0; };
void writeBody() override;
uint32_t registerType(const WasmSignature &Sig);
uint32_t lookupType(const WasmSignature &Sig);
uint32_t registerType(const WasmSignature &sig);
uint32_t lookupType(const WasmSignature &sig);
protected:
std::vector<const WasmSignature *> Types;
llvm::DenseMap<WasmSignature, int32_t> TypeIndices;
std::vector<const WasmSignature *> types;
llvm::DenseMap<WasmSignature, int32_t> typeIndices;
};
class ImportSection : public SyntheticSection {
@ -99,42 +99,42 @@ public:
ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}
bool isNeeded() const override { return getNumImports() > 0; }
void writeBody() override;
void addImport(Symbol *Sym);
void addGOTEntry(Symbol *Sym);
void seal() { IsSealed = true; }
void addImport(Symbol *sym);
void addGOTEntry(Symbol *sym);
void seal() { isSealed = true; }
uint32_t getNumImports() const;
uint32_t getNumImportedGlobals() const {
assert(IsSealed);
return NumImportedGlobals;
assert(isSealed);
return numImportedGlobals;
}
uint32_t getNumImportedFunctions() const {
assert(IsSealed);
return NumImportedFunctions;
assert(isSealed);
return numImportedFunctions;
}
uint32_t getNumImportedEvents() const {
assert(IsSealed);
return NumImportedEvents;
assert(isSealed);
return numImportedEvents;
}
std::vector<const Symbol *> ImportedSymbols;
std::vector<const Symbol *> importedSymbols;
protected:
bool IsSealed = false;
unsigned NumImportedGlobals = 0;
unsigned NumImportedFunctions = 0;
unsigned NumImportedEvents = 0;
std::vector<const Symbol *> GOTSymbols;
bool isSealed = false;
unsigned numImportedGlobals = 0;
unsigned numImportedFunctions = 0;
unsigned numImportedEvents = 0;
std::vector<const Symbol *> gotSymbols;
};
class FunctionSection : public SyntheticSection {
public:
FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {}
bool isNeeded() const override { return InputFunctions.size() > 0; };
bool isNeeded() const override { return inputFunctions.size() > 0; };
void writeBody() override;
void addFunction(InputFunction *Func);
void addFunction(InputFunction *func);
std::vector<InputFunction *> InputFunctions;
std::vector<InputFunction *> inputFunctions;
protected:
};
@ -143,11 +143,11 @@ class MemorySection : public SyntheticSection {
public:
MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
bool isNeeded() const override { return !Config->ImportMemory; }
bool isNeeded() const override { return !config->importMemory; }
void writeBody() override;
uint32_t NumMemoryPages = 0;
uint32_t MaxMemoryPages = 0;
uint32_t numMemoryPages = 0;
uint32_t maxMemoryPages = 0;
};
class TableSection : public SyntheticSection {
@ -163,7 +163,7 @@ public:
// no address-taken function will fail at validation time since it is
// a validation error to include a call_indirect instruction if there
// is not table.
return !Config->ImportTable;
return !config->importTable;
}
void writeBody() override;
@ -173,14 +173,14 @@ class GlobalSection : public SyntheticSection {
public:
GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}
uint32_t numGlobals() const {
return InputGlobals.size() + DefinedFakeGlobals.size();
return inputGlobals.size() + definedFakeGlobals.size();
}
bool isNeeded() const override { return numGlobals() > 0; }
void writeBody() override;
void addGlobal(InputGlobal *Global);
void addGlobal(InputGlobal *global);
std::vector<const DefinedData *> DefinedFakeGlobals;
std::vector<InputGlobal *> InputGlobals;
std::vector<const DefinedData *> definedFakeGlobals;
std::vector<InputGlobal *> inputGlobals;
};
// The event section contains a list of declared wasm events associated with the
@ -197,66 +197,66 @@ class EventSection : public SyntheticSection {
public:
EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {}
void writeBody() override;
bool isNeeded() const override { return InputEvents.size() > 0; }
void addEvent(InputEvent *Event);
bool isNeeded() const override { return inputEvents.size() > 0; }
void addEvent(InputEvent *event);
std::vector<InputEvent *> InputEvents;
std::vector<InputEvent *> inputEvents;
};
class ExportSection : public SyntheticSection {
public:
ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {}
bool isNeeded() const override { return Exports.size() > 0; }
bool isNeeded() const override { return exports.size() > 0; }
void writeBody() override;
std::vector<llvm::wasm::WasmExport> Exports;
std::vector<llvm::wasm::WasmExport> exports;
};
class ElemSection : public SyntheticSection {
public:
ElemSection(uint32_t Offset)
: SyntheticSection(llvm::wasm::WASM_SEC_ELEM), ElemOffset(Offset) {}
bool isNeeded() const override { return IndirectFunctions.size() > 0; };
ElemSection(uint32_t offset)
: SyntheticSection(llvm::wasm::WASM_SEC_ELEM), elemOffset(offset) {}
bool isNeeded() const override { return indirectFunctions.size() > 0; };
void writeBody() override;
void addEntry(FunctionSymbol *Sym);
uint32_t numEntries() const { return IndirectFunctions.size(); }
uint32_t ElemOffset;
void addEntry(FunctionSymbol *sym);
uint32_t numEntries() const { return indirectFunctions.size(); }
uint32_t elemOffset;
protected:
std::vector<const FunctionSymbol *> IndirectFunctions;
std::vector<const FunctionSymbol *> indirectFunctions;
};
class DataCountSection : public SyntheticSection {
public:
DataCountSection(uint32_t NumSegments)
DataCountSection(uint32_t numSegments)
: SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT),
NumSegments(NumSegments) {}
numSegments(numSegments) {}
bool isNeeded() const override;
void writeBody() override;
protected:
uint32_t NumSegments;
uint32_t numSegments;
};
// Create the custom "linking" section containing linker metadata.
// This is only created when relocatable output is requested.
class LinkingSection : public SyntheticSection {
public:
LinkingSection(const std::vector<WasmInitEntry> &InitFunctions,
const std::vector<OutputSegment *> &DataSegments)
LinkingSection(const std::vector<WasmInitEntry> &initFunctions,
const std::vector<OutputSegment *> &dataSegments)
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),
InitFunctions(InitFunctions), DataSegments(DataSegments) {}
initFunctions(initFunctions), dataSegments(dataSegments) {}
bool isNeeded() const override {
return Config->Relocatable || Config->EmitRelocs;
return config->relocatable || config->emitRelocs;
}
void writeBody() override;
void addToSymtab(Symbol *Sym);
void addToSymtab(Symbol *sym);
protected:
std::vector<const Symbol *> SymtabEntries;
llvm::StringMap<uint32_t> SectionSymbolIndices;
const std::vector<WasmInitEntry> &InitFunctions;
const std::vector<OutputSegment *> &DataSegments;
std::vector<const Symbol *> symtabEntries;
llvm::StringMap<uint32_t> sectionSymbolIndices;
const std::vector<WasmInitEntry> &initFunctions;
const std::vector<OutputSegment *> &dataSegments;
};
// Create the custom "name" section containing debug symbol names.
@ -264,7 +264,7 @@ class NameSection : public SyntheticSection {
public:
NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {}
bool isNeeded() const override {
return !Config->StripDebug && !Config->StripAll && numNames() > 0;
return !config->stripDebug && !config->stripAll && numNames() > 0;
}
void writeBody() override;
unsigned numNames() const;
@ -275,18 +275,18 @@ public:
ProducersSection()
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
bool isNeeded() const override {
return !Config->StripAll && fieldCount() > 0;
return !config->stripAll && fieldCount() > 0;
}
void writeBody() override;
void addInfo(const llvm::wasm::WasmProducerInfo &Info);
void addInfo(const llvm::wasm::WasmProducerInfo &info);
protected:
int fieldCount() const {
return int(!Languages.empty()) + int(!Tools.empty()) + int(!SDKs.empty());
return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty());
}
SmallVector<std::pair<std::string, std::string>, 8> Languages;
SmallVector<std::pair<std::string, std::string>, 8> Tools;
SmallVector<std::pair<std::string, std::string>, 8> SDKs;
SmallVector<std::pair<std::string, std::string>, 8> languages;
SmallVector<std::pair<std::string, std::string>, 8> tools;
SmallVector<std::pair<std::string, std::string>, 8> sDKs;
};
class TargetFeaturesSection : public SyntheticSection {
@ -294,44 +294,44 @@ public:
TargetFeaturesSection()
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
bool isNeeded() const override {
return !Config->StripAll && Features.size() > 0;
return !config->stripAll && features.size() > 0;
}
void writeBody() override;
llvm::SmallSet<std::string, 8> Features;
llvm::SmallSet<std::string, 8> features;
};
class RelocSection : public SyntheticSection {
public:
RelocSection(StringRef Name, OutputSection *Sec)
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, Name), Sec(Sec) {}
RelocSection(StringRef name, OutputSection *sec)
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, name), sec(sec) {}
void writeBody() override;
bool isNeeded() const override { return Sec->getNumRelocations() > 0; };
bool isNeeded() const override { return sec->getNumRelocations() > 0; };
protected:
OutputSection *Sec;
OutputSection *sec;
};
// Linker generated output sections
struct OutStruct {
DylinkSection *DylinkSec;
TypeSection *TypeSec;
FunctionSection *FunctionSec;
ImportSection *ImportSec;
TableSection *TableSec;
MemorySection *MemorySec;
GlobalSection *GlobalSec;
EventSection *EventSec;
ExportSection *ExportSec;
ElemSection *ElemSec;
DataCountSection *DataCountSec;
LinkingSection *LinkingSec;
NameSection *NameSec;
ProducersSection *ProducersSec;
TargetFeaturesSection *TargetFeaturesSec;
DylinkSection *dylinkSec;
TypeSection *typeSec;
FunctionSection *functionSec;
ImportSection *importSec;
TableSection *tableSec;
MemorySection *memorySec;
GlobalSection *globalSec;
EventSection *eventSec;
ExportSection *exportSec;
ElemSection *elemSec;
DataCountSection *dataCountSec;
LinkingSection *linkingSec;
NameSection *nameSec;
ProducersSection *producersSec;
TargetFeaturesSection *targetFeaturesSec;
};
extern OutStruct Out;
extern OutStruct out;
} // namespace wasm
} // namespace lld

File diff suppressed because it is too large Load Diff

View File

@ -19,159 +19,159 @@ using namespace llvm::wasm;
namespace lld {
void wasm::debugWrite(uint64_t Offset, const Twine &Msg) {
LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n");
void wasm::debugWrite(uint64_t offset, const Twine &msg) {
LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n");
}
void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
encodeULEB128(Number, OS);
void wasm::writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg) {
debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]");
encodeULEB128(number, os);
}
void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) {
debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
encodeSLEB128(Number, OS);
void wasm::writeSleb128(raw_ostream &os, int32_t number, const Twine &msg) {
debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]");
encodeSLEB128(number, os);
}
void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count,
const Twine &Msg) {
debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]");
OS.write(Bytes, Count);
void wasm::writeBytes(raw_ostream &os, const char *bytes, size_t count,
const Twine &msg) {
debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]");
os.write(bytes, count);
}
void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) {
debugWrite(OS.tell(),
Msg + " [str[" + Twine(String.size()) + "]: " + String + "]");
encodeULEB128(String.size(), OS);
OS.write(String.data(), String.size());
void wasm::writeStr(raw_ostream &os, StringRef string, const Twine &msg) {
debugWrite(os.tell(),
msg + " [str[" + Twine(string.size()) + "]: " + string + "]");
encodeULEB128(string.size(), os);
os.write(string.data(), string.size());
}
void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) {
debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]");
OS << Byte;
void wasm::writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) {
debugWrite(os.tell(), msg + " [0x" + utohexstr(byte) + "]");
os << byte;
}
void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]");
support::endian::write(OS, Number, support::little);
void wasm::writeU32(raw_ostream &os, uint32_t number, const Twine &msg) {
debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]");
support::endian::write(os, number, support::little);
}
void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) {
writeU8(OS, static_cast<uint8_t>(Type),
Msg + "[type: " + toString(Type) + "]");
void wasm::writeValueType(raw_ostream &os, ValType type, const Twine &msg) {
writeU8(os, static_cast<uint8_t>(type),
msg + "[type: " + toString(type) + "]");
}
void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
writeU8(OS, WASM_TYPE_FUNC, "signature type");
writeUleb128(OS, Sig.Params.size(), "param Count");
for (ValType ParamType : Sig.Params) {
writeValueType(OS, ParamType, "param type");
void wasm::writeSig(raw_ostream &os, const WasmSignature &sig) {
writeU8(os, WASM_TYPE_FUNC, "signature type");
writeUleb128(os, sig.Params.size(), "param Count");
for (ValType paramType : sig.Params) {
writeValueType(os, paramType, "param type");
}
writeUleb128(OS, Sig.Returns.size(), "result Count");
if (Sig.Returns.size()) {
writeValueType(OS, Sig.Returns[0], "result type");
writeUleb128(os, sig.Returns.size(), "result Count");
if (sig.Returns.size()) {
writeValueType(os, sig.Returns[0], "result type");
}
}
void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
writeU8(OS, InitExpr.Opcode, "opcode");
switch (InitExpr.Opcode) {
void wasm::writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
writeU8(os, initExpr.Opcode, "opcode");
switch (initExpr.Opcode) {
case WASM_OPCODE_I32_CONST:
writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)");
writeSleb128(os, initExpr.Value.Int32, "literal (i32)");
break;
case WASM_OPCODE_I64_CONST:
writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)");
writeSleb128(os, initExpr.Value.Int64, "literal (i64)");
break;
case WASM_OPCODE_GLOBAL_GET:
writeUleb128(OS, InitExpr.Value.Global, "literal (global index)");
writeUleb128(os, initExpr.Value.Global, "literal (global index)");
break;
default:
fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode));
fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode));
}
writeU8(OS, WASM_OPCODE_END, "opcode:end");
writeU8(os, WASM_OPCODE_END, "opcode:end");
}
void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
writeU8(OS, Limits.Flags, "limits flags");
writeUleb128(OS, Limits.Initial, "limits initial");
if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
writeUleb128(OS, Limits.Maximum, "limits max");
void wasm::writeLimits(raw_ostream &os, const WasmLimits &limits) {
writeU8(os, limits.Flags, "limits flags");
writeUleb128(os, limits.Initial, "limits initial");
if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
writeUleb128(os, limits.Maximum, "limits max");
}
void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) {
void wasm::writeGlobalType(raw_ostream &os, const WasmGlobalType &type) {
// TODO: Update WasmGlobalType to use ValType and remove this cast.
writeValueType(OS, ValType(Type.Type), "global type");
writeU8(OS, Type.Mutable, "global mutable");
writeValueType(os, ValType(type.Type), "global type");
writeU8(os, type.Mutable, "global mutable");
}
void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
writeGlobalType(OS, Global.Type);
writeInitExpr(OS, Global.InitExpr);
void wasm::writeGlobal(raw_ostream &os, const WasmGlobal &global) {
writeGlobalType(os, global.Type);
writeInitExpr(os, global.InitExpr);
}
void wasm::writeEventType(raw_ostream &OS, const WasmEventType &Type) {
writeUleb128(OS, Type.Attribute, "event attribute");
writeUleb128(OS, Type.SigIndex, "sig index");
void wasm::writeEventType(raw_ostream &os, const WasmEventType &type) {
writeUleb128(os, type.Attribute, "event attribute");
writeUleb128(os, type.SigIndex, "sig index");
}
void wasm::writeEvent(raw_ostream &OS, const WasmEvent &Event) {
writeEventType(OS, Event.Type);
void wasm::writeEvent(raw_ostream &os, const WasmEvent &event) {
writeEventType(os, event.Type);
}
void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
writeU8(OS, WASM_TYPE_FUNCREF, "table type");
writeLimits(OS, Type.Limits);
void wasm::writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type) {
writeU8(os, WASM_TYPE_FUNCREF, "table type");
writeLimits(os, type.Limits);
}
void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
writeStr(OS, Import.Module, "import module name");
writeStr(OS, Import.Field, "import field name");
writeU8(OS, Import.Kind, "import kind");
switch (Import.Kind) {
void wasm::writeImport(raw_ostream &os, const WasmImport &import) {
writeStr(os, import.Module, "import module name");
writeStr(os, import.Field, "import field name");
writeU8(os, import.Kind, "import kind");
switch (import.Kind) {
case WASM_EXTERNAL_FUNCTION:
writeUleb128(OS, Import.SigIndex, "import sig index");
writeUleb128(os, import.SigIndex, "import sig index");
break;
case WASM_EXTERNAL_GLOBAL:
writeGlobalType(OS, Import.Global);
writeGlobalType(os, import.Global);
break;
case WASM_EXTERNAL_EVENT:
writeEventType(OS, Import.Event);
writeEventType(os, import.Event);
break;
case WASM_EXTERNAL_MEMORY:
writeLimits(OS, Import.Memory);
writeLimits(os, import.Memory);
break;
case WASM_EXTERNAL_TABLE:
writeTableType(OS, Import.Table);
writeTableType(os, import.Table);
break;
default:
fatal("unsupported import type: " + Twine(Import.Kind));
fatal("unsupported import type: " + Twine(import.Kind));
}
}
void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
writeStr(OS, Export.Name, "export name");
writeU8(OS, Export.Kind, "export kind");
switch (Export.Kind) {
void wasm::writeExport(raw_ostream &os, const WasmExport &export_) {
writeStr(os, export_.Name, "export name");
writeU8(os, export_.Kind, "export kind");
switch (export_.Kind) {
case WASM_EXTERNAL_FUNCTION:
writeUleb128(OS, Export.Index, "function index");
writeUleb128(os, export_.Index, "function index");
break;
case WASM_EXTERNAL_GLOBAL:
writeUleb128(OS, Export.Index, "global index");
writeUleb128(os, export_.Index, "global index");
break;
case WASM_EXTERNAL_MEMORY:
writeUleb128(OS, Export.Index, "memory index");
writeUleb128(os, export_.Index, "memory index");
break;
case WASM_EXTERNAL_TABLE:
writeUleb128(OS, Export.Index, "table index");
writeUleb128(os, export_.Index, "table index");
break;
default:
fatal("unsupported export type: " + Twine(Export.Kind));
fatal("unsupported export type: " + Twine(export_.Kind));
}
}
} // namespace lld
std::string lld::toString(ValType Type) {
switch (Type) {
std::string lld::toString(ValType type) {
switch (type) {
case ValType::I32:
return "i32";
case ValType::I64:
@ -188,28 +188,28 @@ std::string lld::toString(ValType Type) {
llvm_unreachable("Invalid wasm::ValType");
}
std::string lld::toString(const WasmSignature &Sig) {
SmallString<128> S("(");
for (ValType Type : Sig.Params) {
if (S.size() != 1)
S += ", ";
S += toString(Type);
std::string lld::toString(const WasmSignature &sig) {
SmallString<128> s("(");
for (ValType type : sig.Params) {
if (s.size() != 1)
s += ", ";
s += toString(type);
}
S += ") -> ";
if (Sig.Returns.empty())
S += "void";
s += ") -> ";
if (sig.Returns.empty())
s += "void";
else
S += toString(Sig.Returns[0]);
return S.str();
s += toString(sig.Returns[0]);
return s.str();
}
std::string lld::toString(const WasmGlobalType &Type) {
return (Type.Mutable ? "var " : "const ") +
toString(static_cast<ValType>(Type.Type));
std::string lld::toString(const WasmGlobalType &type) {
return (type.Mutable ? "var " : "const ") +
toString(static_cast<ValType>(type.Type));
}
std::string lld::toString(const WasmEventType &Type) {
if (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
std::string lld::toString(const WasmEventType &type) {
if (type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
return "exception";
return "unknown";
}

View File

@ -16,50 +16,50 @@
namespace lld {
namespace wasm {
void debugWrite(uint64_t Offset, const Twine &Msg);
void debugWrite(uint64_t offset, const Twine &msg);
void writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg);
void writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg);
void writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg);
void writeSleb128(raw_ostream &os, int32_t number, const Twine &msg);
void writeBytes(raw_ostream &OS, const char *Bytes, size_t count,
const Twine &Msg);
void writeBytes(raw_ostream &os, const char *bytes, size_t count,
const Twine &msg);
void writeStr(raw_ostream &OS, StringRef String, const Twine &Msg);
void writeStr(raw_ostream &os, StringRef string, const Twine &msg);
void writeU8(raw_ostream &OS, uint8_t byte, const Twine &Msg);
void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg);
void writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg);
void writeU32(raw_ostream &os, uint32_t number, const Twine &msg);
void writeValueType(raw_ostream &OS, llvm::wasm::ValType Type,
const Twine &Msg);
void writeValueType(raw_ostream &os, llvm::wasm::ValType type,
const Twine &msg);
void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig);
void writeSig(raw_ostream &os, const llvm::wasm::WasmSignature &sig);
void writeInitExpr(raw_ostream &OS, const llvm::wasm::WasmInitExpr &InitExpr);
void writeInitExpr(raw_ostream &os, const llvm::wasm::WasmInitExpr &initExpr);
void writeLimits(raw_ostream &OS, const llvm::wasm::WasmLimits &Limits);
void writeLimits(raw_ostream &os, const llvm::wasm::WasmLimits &limits);
void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type);
void writeGlobalType(raw_ostream &os, const llvm::wasm::WasmGlobalType &type);
void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global);
void writeGlobal(raw_ostream &os, const llvm::wasm::WasmGlobal &global);
void writeEventType(raw_ostream &OS, const llvm::wasm::WasmEventType &Type);
void writeEventType(raw_ostream &os, const llvm::wasm::WasmEventType &type);
void writeEvent(raw_ostream &OS, const llvm::wasm::WasmEvent &Event);
void writeEvent(raw_ostream &os, const llvm::wasm::WasmEvent &event);
void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type);
void writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type);
void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
void writeImport(raw_ostream &os, const llvm::wasm::WasmImport &import);
void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
void writeExport(raw_ostream &os, const llvm::wasm::WasmExport &export_);
} // namespace wasm
std::string toString(llvm::wasm::ValType Type);
std::string toString(const llvm::wasm::WasmSignature &Sig);
std::string toString(const llvm::wasm::WasmGlobalType &Type);
std::string toString(const llvm::wasm::WasmEventType &Type);
std::string toString(llvm::wasm::ValType type);
std::string toString(const llvm::wasm::WasmSignature &sig);
std::string toString(const llvm::wasm::WasmGlobalType &type);
std::string toString(const llvm::wasm::WasmEventType &type);
} // namespace lld