mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-31 16:57:10 +00:00
Vendor import of lld trunk r307894:
https://llvm.org/svn/llvm-project/lld/trunk@307894
This commit is contained in:
parent
0317860f00
commit
2678297743
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/lld/dist/; revision=320965 svn path=/vendor/lld/lld-trunk-r307894/; revision=320966; tag=vendor/lld/lld-trunk-r307894
@ -52,6 +52,7 @@ static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
|
||||
static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
|
||||
static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
|
||||
static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
|
||||
static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
|
||||
|
||||
static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
|
||||
OutputSection *OS, uint64_t S) {
|
||||
@ -166,6 +167,41 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
|
||||
}
|
||||
}
|
||||
|
||||
static void applyArm64Addr(uint8_t *Off, uint64_t Imm) {
|
||||
uint32_t ImmLo = (Imm & 0x3) << 29;
|
||||
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
|
||||
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
|
||||
write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi);
|
||||
}
|
||||
|
||||
// Update the immediate field in a AARCH64 ldr, str, and add instruction.
|
||||
static void applyArm64Imm(uint8_t *Off, uint64_t Imm) {
|
||||
uint32_t Orig = read32le(Off);
|
||||
Imm += (Orig >> 10) & 0xFFF;
|
||||
Orig &= ~(0xFFF << 10);
|
||||
write32le(Off, Orig | ((Imm & 0xFFF) << 10));
|
||||
}
|
||||
|
||||
static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
|
||||
int Size = read32le(Off) >> 30;
|
||||
Imm >>= Size;
|
||||
applyArm64Imm(Off, Imm);
|
||||
}
|
||||
|
||||
void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
|
||||
uint64_t S, uint64_t P) const {
|
||||
switch (Type) {
|
||||
case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, (S >> 12) - (P >> 12)); break;
|
||||
case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); break;
|
||||
case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
|
||||
case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
|
||||
case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
|
||||
case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
|
||||
default:
|
||||
fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
|
||||
}
|
||||
}
|
||||
|
||||
void SectionChunk::writeTo(uint8_t *Buf) const {
|
||||
if (!hasData())
|
||||
return;
|
||||
@ -210,6 +246,9 @@ void SectionChunk::writeTo(uint8_t *Buf) const {
|
||||
case ARMNT:
|
||||
applyRelARM(Off, Rel.Type, OS, S, P);
|
||||
break;
|
||||
case ARM64:
|
||||
applyRelARM64(Off, Rel.Type, OS, S, P);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unknown machine type");
|
||||
}
|
||||
@ -236,6 +275,10 @@ static uint8_t getBaserelType(const coff_relocation &Rel) {
|
||||
if (Rel.Type == IMAGE_REL_ARM_MOV32T)
|
||||
return IMAGE_REL_BASED_ARM_MOV32T;
|
||||
return IMAGE_REL_BASED_ABSOLUTE;
|
||||
case ARM64:
|
||||
if (Rel.Type == IMAGE_REL_ARM64_ADDR64)
|
||||
return IMAGE_REL_BASED_DIR64;
|
||||
return IMAGE_REL_BASED_ABSOLUTE;
|
||||
default:
|
||||
llvm_unreachable("unknown machine type");
|
||||
}
|
||||
@ -345,6 +388,14 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
|
||||
applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
|
||||
}
|
||||
|
||||
void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
|
||||
int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12);
|
||||
int64_t Off = ImpSymbol->getRVA() & 0xfff;
|
||||
memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
|
||||
applyArm64Addr(Buf + OutputSectionOff, PageOff);
|
||||
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
|
||||
}
|
||||
|
||||
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
|
||||
Res->emplace_back(getRVA());
|
||||
}
|
||||
|
@ -151,6 +151,8 @@ class SectionChunk : public Chunk {
|
||||
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;
|
||||
|
||||
// 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.
|
||||
@ -264,6 +266,12 @@ static const uint8_t ImportThunkARM[] = {
|
||||
0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
// Windows-specific.
|
||||
// A chunk for DLL import jump table entry. In a final output, it's
|
||||
// contents will be a JMP instruction to some __imp_ symbol.
|
||||
@ -299,6 +307,16 @@ class ImportThunkChunkARM : public Chunk {
|
||||
Defined *ImpSymbol;
|
||||
};
|
||||
|
||||
class ImportThunkChunkARM64 : public Chunk {
|
||||
public:
|
||||
explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {}
|
||||
size_t getSize() const override { return sizeof(ImportThunkARM64); }
|
||||
void writeTo(uint8_t *Buf) const override;
|
||||
|
||||
private:
|
||||
Defined *ImpSymbol;
|
||||
};
|
||||
|
||||
// Windows-specific.
|
||||
// See comments for DefinedLocalImport class.
|
||||
class LocalImportChunk : public Chunk {
|
||||
|
@ -31,6 +31,7 @@ class SymbolBody;
|
||||
|
||||
// Short aliases.
|
||||
static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
|
||||
static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64;
|
||||
static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
|
||||
static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
|
||||
|
||||
@ -73,7 +74,7 @@ enum class DebugType {
|
||||
// Global configuration.
|
||||
struct Configuration {
|
||||
enum ManifestKind { SideBySide, Embed, No };
|
||||
bool is64() { return Machine == AMD64; }
|
||||
bool is64() { return Machine == AMD64 || Machine == ARM64; }
|
||||
|
||||
llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
|
||||
bool Verbose = false;
|
||||
@ -91,6 +92,7 @@ struct Configuration {
|
||||
bool WriteSymtab = true;
|
||||
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
|
||||
llvm::SmallString<128> PDBPath;
|
||||
std::vector<llvm::StringRef> Argv;
|
||||
|
||||
// Symbols in this set are considered as live by the garbage collector.
|
||||
std::set<SymbolBody *> GCRoot;
|
||||
|
@ -55,8 +55,8 @@ std::vector<SpecificAllocBase *> SpecificAllocBase::Instances;
|
||||
bool link(ArrayRef<const char *> Args, raw_ostream &Diag) {
|
||||
ErrorCount = 0;
|
||||
ErrorOS = &Diag;
|
||||
Argv0 = Args[0];
|
||||
Config = make<Configuration>();
|
||||
Config->Argv = {Args.begin(), Args.end()};
|
||||
Config->ColorDiagnostics =
|
||||
(ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
|
||||
Driver = make<LinkerDriver>();
|
||||
|
@ -85,6 +85,7 @@ MachineTypes getMachineType(StringRef S) {
|
||||
.Cases("x64", "amd64", AMD64)
|
||||
.Cases("x86", "i386", I386)
|
||||
.Case("arm", ARMNT)
|
||||
.Case("arm64", ARM64)
|
||||
.Default(IMAGE_FILE_MACHINE_UNKNOWN);
|
||||
if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
|
||||
return MT;
|
||||
@ -95,6 +96,8 @@ StringRef machineToStr(MachineTypes MT) {
|
||||
switch (MT) {
|
||||
case ARMNT:
|
||||
return "arm";
|
||||
case ARM64:
|
||||
return "arm64";
|
||||
case AMD64:
|
||||
return "x64";
|
||||
case I386:
|
||||
@ -378,13 +381,11 @@ static std::string createManifestXml() {
|
||||
|
||||
static std::unique_ptr<MemoryBuffer>
|
||||
createMemoryBufferForManifestRes(size_t ManifestSize) {
|
||||
size_t ResSize = alignTo(object::WIN_RES_MAGIC_SIZE +
|
||||
object::WIN_RES_NULL_ENTRY_SIZE +
|
||||
sizeof(object::WinResHeaderPrefix) +
|
||||
sizeof(object::WinResIDs) +
|
||||
sizeof(object::WinResHeaderSuffix) +
|
||||
ManifestSize,
|
||||
object::WIN_RES_DATA_ALIGNMENT);
|
||||
size_t ResSize = alignTo(
|
||||
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
|
||||
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
|
||||
sizeof(object::WinResHeaderSuffix) + ManifestSize,
|
||||
object::WIN_RES_DATA_ALIGNMENT);
|
||||
return MemoryBuffer::getNewMemBuffer(ResSize);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@ namespace lld {
|
||||
static std::mutex Mu;
|
||||
|
||||
namespace coff {
|
||||
StringRef Argv0;
|
||||
uint64_t ErrorCount;
|
||||
raw_ostream *ErrorOS;
|
||||
|
||||
@ -45,7 +44,7 @@ static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
|
||||
}
|
||||
|
||||
static void print(StringRef S, raw_ostream::Colors C) {
|
||||
*ErrorOS << Argv0 + ": ";
|
||||
*ErrorOS << Config->Argv[0] << ": ";
|
||||
if (Config->ColorDiagnostics) {
|
||||
ErrorOS->changeColor(C, true);
|
||||
*ErrorOS << S;
|
||||
@ -58,7 +57,7 @@ static void print(StringRef S, raw_ostream::Colors C) {
|
||||
void log(const Twine &Msg) {
|
||||
if (Config->Verbose) {
|
||||
std::lock_guard<std::mutex> Lock(Mu);
|
||||
outs() << Argv0 << ": " << Msg << "\n";
|
||||
outs() << Config->Argv[0] << ": " << Msg << "\n";
|
||||
outs().flush();
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ namespace coff {
|
||||
|
||||
extern uint64_t ErrorCount;
|
||||
extern llvm::raw_ostream *ErrorOS;
|
||||
extern llvm::StringRef Argv0;
|
||||
|
||||
void log(const Twine &Msg);
|
||||
void message(const Twine &Msg);
|
||||
|
@ -380,6 +380,8 @@ MachineTypes BitcodeFile::getMachineType() {
|
||||
return I386;
|
||||
case Triple::arm:
|
||||
return ARMNT;
|
||||
case Triple::aarch64:
|
||||
return ARM64;
|
||||
default:
|
||||
return IMAGE_FILE_MACHINE_UNKNOWN;
|
||||
}
|
||||
|
174
COFF/PDB.cpp
174
COFF/PDB.cpp
@ -18,19 +18,20 @@
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFCommon.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||
@ -124,26 +125,25 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool remapTypesInSymbolRecord(ObjectFile *File,
|
||||
static void remapTypesInSymbolRecord(ObjectFile *File,
|
||||
MutableArrayRef<uint8_t> Contents,
|
||||
ArrayRef<TypeIndex> TypeIndexMap,
|
||||
ArrayRef<TiReference> TypeRefs) {
|
||||
for (const TiReference &Ref : TypeRefs) {
|
||||
unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
|
||||
if (Contents.size() < Ref.Offset + ByteSize) {
|
||||
log("ignoring short symbol record");
|
||||
return false;
|
||||
}
|
||||
if (Contents.size() < Ref.Offset + ByteSize)
|
||||
fatal("symbol record too short");
|
||||
MutableArrayRef<TypeIndex> TIs(
|
||||
reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
|
||||
for (TypeIndex &TI : TIs)
|
||||
for (TypeIndex &TI : TIs) {
|
||||
if (!remapTypeIndex(TI, TypeIndexMap)) {
|
||||
TI = TypeIndex(SimpleTypeKind::NotTranslated);
|
||||
log("ignoring symbol record in " + File->getName() +
|
||||
" with bad type index 0x" + utohexstr(TI.getIndex()));
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// MSVC translates S_PROC_ID_END to S_END.
|
||||
@ -176,6 +176,70 @@ static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym,
|
||||
return NewData;
|
||||
}
|
||||
|
||||
/// Return true if this symbol opens a scope. This implies that the symbol has
|
||||
/// "parent" and "end" fields, which contain the offset of the S_END or
|
||||
/// S_INLINESITE_END record.
|
||||
static bool symbolOpensScope(SymbolKind Kind) {
|
||||
switch (Kind) {
|
||||
case SymbolKind::S_GPROC32:
|
||||
case SymbolKind::S_LPROC32:
|
||||
case SymbolKind::S_LPROC32_ID:
|
||||
case SymbolKind::S_GPROC32_ID:
|
||||
case SymbolKind::S_BLOCK32:
|
||||
case SymbolKind::S_SEPCODE:
|
||||
case SymbolKind::S_THUNK32:
|
||||
case SymbolKind::S_INLINESITE:
|
||||
case SymbolKind::S_INLINESITE2:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool symbolEndsScope(SymbolKind Kind) {
|
||||
switch (Kind) {
|
||||
case SymbolKind::S_END:
|
||||
case SymbolKind::S_PROC_ID_END:
|
||||
case SymbolKind::S_INLINESITE_END:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ScopeRecord {
|
||||
ulittle32_t PtrParent;
|
||||
ulittle32_t PtrEnd;
|
||||
};
|
||||
|
||||
struct SymbolScope {
|
||||
ScopeRecord *OpeningRecord;
|
||||
uint32_t ScopeOffset;
|
||||
};
|
||||
|
||||
static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack,
|
||||
uint32_t CurOffset, CVSymbol &Sym) {
|
||||
assert(symbolOpensScope(Sym.kind()));
|
||||
SymbolScope S;
|
||||
S.ScopeOffset = CurOffset;
|
||||
S.OpeningRecord = const_cast<ScopeRecord *>(
|
||||
reinterpret_cast<const ScopeRecord *>(Sym.content().data()));
|
||||
S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset;
|
||||
Stack.push_back(S);
|
||||
}
|
||||
|
||||
static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
|
||||
uint32_t CurOffset, ObjectFile *File) {
|
||||
if (Stack.empty()) {
|
||||
warn("symbol scopes are not balanced in " + File->getName());
|
||||
return;
|
||||
}
|
||||
SymbolScope S = Stack.pop_back_val();
|
||||
S.OpeningRecord->PtrEnd = CurOffset;
|
||||
}
|
||||
|
||||
static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
|
||||
ArrayRef<TypeIndex> TypeIndexMap,
|
||||
BinaryStreamRef SymData) {
|
||||
@ -184,6 +248,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
|
||||
CVSymbolArray Syms;
|
||||
BinaryStreamReader Reader(SymData);
|
||||
ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
|
||||
SmallVector<SymbolScope, 4> Scopes;
|
||||
for (const CVSymbol &Sym : Syms) {
|
||||
// Discover type index references in the record. Skip it if we don't know
|
||||
// where they are.
|
||||
@ -199,14 +264,17 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
|
||||
// Re-map all the type index references.
|
||||
MutableArrayRef<uint8_t> Contents =
|
||||
NewData.drop_front(sizeof(RecordPrefix));
|
||||
if (!remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs))
|
||||
continue;
|
||||
remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs);
|
||||
|
||||
// FIXME: Fill in "Parent" and "End" fields by maintaining a stack of
|
||||
// scopes.
|
||||
// Fill in "Parent" and "End" fields by maintaining a stack of scopes.
|
||||
CVSymbol NewSym(Sym.kind(), NewData);
|
||||
if (symbolOpensScope(Sym.kind()))
|
||||
scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
|
||||
else if (symbolEndsScope(Sym.kind()))
|
||||
scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
|
||||
|
||||
// Add the symbol to the module.
|
||||
File->ModuleDBI->addSymbol(CVSymbol(Sym.kind(), NewData));
|
||||
File->ModuleDBI->addSymbol(NewSym);
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +314,9 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab,
|
||||
bool InArchive = !File->ParentName.empty();
|
||||
SmallString<128> Path = InArchive ? File->ParentName : File->getName();
|
||||
sys::fs::make_absolute(Path);
|
||||
sys::path::native(Path, llvm::sys::path::Style::windows);
|
||||
StringRef Name = InArchive ? File->getName() : StringRef(Path);
|
||||
|
||||
File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
|
||||
File->ModuleDBI->setObjFileName(Path);
|
||||
|
||||
@ -325,9 +395,52 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab,
|
||||
addTypeInfo(Builder.getIpiBuilder(), IDTable);
|
||||
}
|
||||
|
||||
static void addLinkerModuleSymbols(StringRef Path,
|
||||
pdb::DbiModuleDescriptorBuilder &Mod,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb);
|
||||
codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
|
||||
codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym);
|
||||
codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym);
|
||||
|
||||
ONS.Name = "* Linker *";
|
||||
ONS.Signature = 0;
|
||||
|
||||
CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
|
||||
CS.Flags = CompileSym3Flags::None;
|
||||
CS.VersionBackendBuild = 0;
|
||||
CS.VersionBackendMajor = 0;
|
||||
CS.VersionBackendMinor = 0;
|
||||
CS.VersionBackendQFE = 0;
|
||||
CS.VersionFrontendBuild = 0;
|
||||
CS.VersionFrontendMajor = 0;
|
||||
CS.VersionFrontendMinor = 0;
|
||||
CS.VersionFrontendQFE = 0;
|
||||
CS.Version = "LLVM Linker";
|
||||
CS.setLanguage(SourceLanguage::Link);
|
||||
|
||||
ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
|
||||
std::string ArgStr = llvm::join(Args, " ");
|
||||
EBS.Fields.push_back("cwd");
|
||||
SmallString<64> cwd;
|
||||
llvm::sys::fs::current_path(cwd);
|
||||
EBS.Fields.push_back(cwd);
|
||||
EBS.Fields.push_back("exe");
|
||||
EBS.Fields.push_back(Config->Argv[0]);
|
||||
EBS.Fields.push_back("pdb");
|
||||
EBS.Fields.push_back(Path);
|
||||
EBS.Fields.push_back("cmd");
|
||||
EBS.Fields.push_back(ArgStr);
|
||||
Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
|
||||
ONS, Allocator, CodeViewContainer::Pdb));
|
||||
Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
|
||||
CS, Allocator, CodeViewContainer::Pdb));
|
||||
Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
|
||||
EBS, Allocator, CodeViewContainer::Pdb));
|
||||
}
|
||||
|
||||
// Creates a PDB file.
|
||||
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
|
||||
ArrayRef<uint8_t> SectionTable,
|
||||
void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable,
|
||||
const llvm::codeview::DebugInfo *DI) {
|
||||
BumpPtrAllocator Alloc;
|
||||
pdb::PDBFileBuilder Builder(Alloc);
|
||||
@ -342,22 +455,37 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
|
||||
auto &InfoBuilder = Builder.getInfoBuilder();
|
||||
InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
|
||||
|
||||
llvm::SmallString<128> NativePath(Config->PDBPath.begin(),
|
||||
Config->PDBPath.end());
|
||||
llvm::sys::fs::make_absolute(NativePath);
|
||||
llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows);
|
||||
|
||||
pdb::PDB_UniqueId uuid{};
|
||||
if (DI)
|
||||
memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
|
||||
InfoBuilder.setGuid(uuid);
|
||||
// Should be the current time, but set 0 for reproducibilty.
|
||||
InfoBuilder.setSignature(0);
|
||||
InfoBuilder.setSignature(time(nullptr));
|
||||
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
|
||||
|
||||
// Add an empty DPI stream.
|
||||
// Add an empty DBI stream.
|
||||
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
|
||||
DbiBuilder.setVersionHeader(pdb::PdbDbiV110);
|
||||
DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
|
||||
ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
|
||||
|
||||
// It's not entirely clear what this is, but the * Linker * module uses it.
|
||||
uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
|
||||
|
||||
TypeTableBuilder TypeTable(BAlloc);
|
||||
TypeTableBuilder IDTable(BAlloc);
|
||||
addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable);
|
||||
|
||||
// Add public and symbol records stream.
|
||||
|
||||
// For now we don't actually write any thing useful to the publics stream, but
|
||||
// the act of "getting" it also creates it lazily so that we write an empty
|
||||
// stream.
|
||||
(void)Builder.getPublicsBuilder();
|
||||
|
||||
// Add Section Contributions.
|
||||
addSectionContribs(Symtab, DbiBuilder);
|
||||
|
||||
@ -369,12 +497,14 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
|
||||
pdb::DbiStreamBuilder::createSectionMap(Sections);
|
||||
DbiBuilder.setSectionMap(SectionMap);
|
||||
|
||||
ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
|
||||
auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
|
||||
LinkerModule.setPdbFilePathNI(PdbFilePathNI);
|
||||
addLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
|
||||
|
||||
// Add COFF section header stream.
|
||||
ExitOnErr(
|
||||
DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
|
||||
|
||||
// Write to a file.
|
||||
ExitOnErr(Builder.commit(Path));
|
||||
ExitOnErr(Builder.commit(Config->PDBPath));
|
||||
}
|
||||
|
@ -23,8 +23,7 @@ namespace lld {
|
||||
namespace coff {
|
||||
class SymbolTable;
|
||||
|
||||
void createPDB(llvm::StringRef Path, SymbolTable *Symtab,
|
||||
llvm::ArrayRef<uint8_t> SectionTable,
|
||||
void createPDB(SymbolTable *Symtab, llvm::ArrayRef<uint8_t> SectionTable,
|
||||
const llvm::codeview::DebugInfo *DI);
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,8 @@ static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
|
||||
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);
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ void Writer::run() {
|
||||
const llvm::codeview::DebugInfo *DI = nullptr;
|
||||
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
|
||||
DI = BuildId->DI;
|
||||
createPDB(Config->PDBPath, Symtab, SectionTable, DI);
|
||||
createPDB(Symtab, SectionTable, DI);
|
||||
}
|
||||
|
||||
writeMapFile(OutputSections);
|
||||
|
@ -97,6 +97,7 @@ struct Configuration {
|
||||
llvm::StringRef ThinLTOCacheDir;
|
||||
std::string Rpath;
|
||||
std::vector<VersionDefinition> VersionDefinitions;
|
||||
std::vector<llvm::StringRef> Argv;
|
||||
std::vector<llvm::StringRef> AuxiliaryList;
|
||||
std::vector<llvm::StringRef> SearchPaths;
|
||||
std::vector<llvm::StringRef> SymbolOrderingFile;
|
||||
|
@ -74,13 +74,13 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
|
||||
raw_ostream &Error) {
|
||||
ErrorCount = 0;
|
||||
ErrorOS = &Error;
|
||||
Argv0 = Args[0];
|
||||
InputSections.clear();
|
||||
Tar = nullptr;
|
||||
|
||||
Config = make<Configuration>();
|
||||
Driver = make<LinkerDriver>();
|
||||
Script = make<LinkerScript>();
|
||||
Config->Argv = {Args.begin(), Args.end()};
|
||||
|
||||
Driver->main(Args, CanExitEarly);
|
||||
freeArena();
|
||||
|
@ -27,7 +27,6 @@ using namespace lld::elf;
|
||||
|
||||
uint64_t elf::ErrorCount;
|
||||
raw_ostream *elf::ErrorOS;
|
||||
StringRef elf::Argv0;
|
||||
|
||||
// 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.
|
||||
@ -46,7 +45,7 @@ static void newline(const Twine &Msg) {
|
||||
}
|
||||
|
||||
static void print(StringRef S, raw_ostream::Colors C) {
|
||||
*ErrorOS << Argv0 + ": ";
|
||||
*ErrorOS << Config->Argv[0] << ": ";
|
||||
if (Config->ColorDiagnostics) {
|
||||
ErrorOS->changeColor(C, true);
|
||||
*ErrorOS << S;
|
||||
@ -59,7 +58,7 @@ static void print(StringRef S, raw_ostream::Colors C) {
|
||||
void elf::log(const Twine &Msg) {
|
||||
if (Config->Verbose) {
|
||||
std::lock_guard<std::mutex> Lock(Mu);
|
||||
outs() << Argv0 << ": " << Msg << "\n";
|
||||
outs() << Config->Argv[0] << ": " << Msg << "\n";
|
||||
outs().flush();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ namespace elf {
|
||||
|
||||
extern uint64_t ErrorCount;
|
||||
extern llvm::raw_ostream *ErrorOS;
|
||||
extern llvm::StringRef Argv0;
|
||||
|
||||
void log(const Twine &Msg);
|
||||
void message(const Twine &Msg);
|
||||
|
@ -38,7 +38,8 @@ using namespace lld::elf;
|
||||
// This function spawns a background thread to call unlink.
|
||||
// The calling thread returns almost immediately.
|
||||
void elf::unlinkAsync(StringRef Path) {
|
||||
if (!Config->Threads || !sys::fs::exists(Config->OutputFile))
|
||||
if (!Config->Threads || !sys::fs::exists(Config->OutputFile) ||
|
||||
!sys::fs::is_regular_file(Config->OutputFile))
|
||||
return;
|
||||
|
||||
// First, rename Path to avoid race condition. We cannot remove
|
||||
|
@ -45,6 +45,7 @@ struct NameTypeEntry {
|
||||
// debug information performed. That information futher used
|
||||
// for filling gdb index section areas.
|
||||
struct GdbIndexChunk {
|
||||
InputSection *DebugInfoSec;
|
||||
std::vector<AddressEntry> AddressArea;
|
||||
std::vector<CompilationUnitEntry> CompilationUnits;
|
||||
std::vector<NameTypeEntry> NamesAndTypes;
|
||||
|
@ -45,14 +45,11 @@ namespace {
|
||||
// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
|
||||
// we assign each section some unique address. This callback method assigns
|
||||
// each section an address equal to its offset in ELF object file.
|
||||
class ObjectInfo : public LoadedObjectInfo {
|
||||
class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> {
|
||||
public:
|
||||
uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
|
||||
return static_cast<const ELFSectionRef &>(Sec).getOffset();
|
||||
}
|
||||
std::unique_ptr<LoadedObjectInfo> clone() const override {
|
||||
return std::unique_ptr<LoadedObjectInfo>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,9 @@ template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) {
|
||||
template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) {
|
||||
// Synthetic sections don't have input files.
|
||||
elf::ObjectFile<ELFT> *File = getFile<ELFT>();
|
||||
std::string Filename = File ? File->getName() : "(internal)";
|
||||
if (!File)
|
||||
return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str();
|
||||
std::string Filename = File->getName();
|
||||
|
||||
std::string Archive;
|
||||
if (!File->ArchiveName.empty())
|
||||
@ -466,7 +468,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
|
||||
static uint64_t getARMStaticBase(const SymbolBody &Body) {
|
||||
OutputSection *OS = Body.getOutputSection();
|
||||
if (!OS || !OS->FirstInPtLoad)
|
||||
fatal("SBREL relocation to " + Body.getName() + " without static base\n");
|
||||
fatal("SBREL relocation to " + Body.getName() + " without static base");
|
||||
return OS->FirstInPtLoad->Addr;
|
||||
}
|
||||
|
||||
|
@ -111,17 +111,13 @@ LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
|
||||
|
||||
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
|
||||
uint64_t Val = E().getValue();
|
||||
if (Val < Dot) {
|
||||
if (InSec)
|
||||
error(Loc + ": unable to move location counter backward for: " +
|
||||
CurOutSec->Name);
|
||||
else
|
||||
error(Loc + ": unable to move location counter backward");
|
||||
}
|
||||
if (Val < Dot && InSec)
|
||||
error(Loc + ": unable to move location counter backward for: " +
|
||||
CurAddressState->OutSec->Name);
|
||||
Dot = Val;
|
||||
// Update to location counter means update to section size.
|
||||
if (InSec)
|
||||
CurOutSec->Size = Dot - CurOutSec->Addr;
|
||||
CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
|
||||
}
|
||||
|
||||
// Sets value of a symbol. Two kinds of symbols are processed: synthetic
|
||||
@ -373,7 +369,13 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
|
||||
// which will map to whatever the first actual section is.
|
||||
Aether = make<OutputSection>("", 0, SHF_ALLOC);
|
||||
Aether->SectionIndex = 1;
|
||||
CurOutSec = Aether;
|
||||
auto State = make_unique<AddressState>(Opt);
|
||||
// CurAddressState captures the local AddressState and makes it accessible
|
||||
// deliberately. This is needed as there are some cases where we cannot just
|
||||
// thread the current state through to a lambda function created by the
|
||||
// script parser.
|
||||
CurAddressState = State.get();
|
||||
CurAddressState->OutSec = Aether;
|
||||
Dot = 0;
|
||||
|
||||
for (size_t I = 0; I < Opt.Commands.size(); ++I) {
|
||||
@ -435,7 +437,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
|
||||
}
|
||||
}
|
||||
}
|
||||
CurOutSec = nullptr;
|
||||
CurAddressState = nullptr;
|
||||
}
|
||||
|
||||
void LinkerScript::fabricateDefaultCommands() {
|
||||
@ -481,20 +483,31 @@ void LinkerScript::fabricateDefaultCommands() {
|
||||
|
||||
// Add sections that didn't match any sections command.
|
||||
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
||||
unsigned NumCommands = Opt.Commands.size();
|
||||
for (InputSectionBase *S : InputSections) {
|
||||
if (!S->Live || S->Parent)
|
||||
continue;
|
||||
StringRef Name = getOutputSectionName(S->Name);
|
||||
auto I = std::find_if(
|
||||
Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
|
||||
return Cmd->Name == Name;
|
||||
return false;
|
||||
});
|
||||
if (I == Opt.Commands.end()) {
|
||||
auto End = Opt.Commands.begin() + NumCommands;
|
||||
auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) {
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
|
||||
return Cmd->Name == Name;
|
||||
return false;
|
||||
});
|
||||
OutputSectionCommand *Cmd;
|
||||
if (I == End) {
|
||||
Factory.addInputSec(S, Name);
|
||||
OutputSection *Sec = S->getOutputSection();
|
||||
assert(Sec->SectionIndex == INT_MAX);
|
||||
OutputSectionCommand *&CmdRef = SecToCommand[Sec];
|
||||
if (!CmdRef) {
|
||||
CmdRef = createOutputSectionCommand(Sec->Name, "<internal>");
|
||||
CmdRef->Sec = Sec;
|
||||
Opt.Commands.push_back(CmdRef);
|
||||
}
|
||||
Cmd = CmdRef;
|
||||
} else {
|
||||
auto *Cmd = cast<OutputSectionCommand>(*I);
|
||||
Cmd = cast<OutputSectionCommand>(*I);
|
||||
Factory.addInputSec(S, Name, Cmd->Sec);
|
||||
if (OutputSection *Sec = Cmd->Sec) {
|
||||
SecToCommand[Sec] = Cmd;
|
||||
@ -502,21 +515,22 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
||||
assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
|
||||
Sec->SectionIndex = Index;
|
||||
}
|
||||
auto *ISD = make<InputSectionDescription>("");
|
||||
ISD->Sections.push_back(cast<InputSection>(S));
|
||||
Cmd->Commands.push_back(ISD);
|
||||
}
|
||||
auto *ISD = make<InputSectionDescription>("");
|
||||
ISD->Sections.push_back(cast<InputSection>(S));
|
||||
Cmd->Commands.push_back(ISD);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
|
||||
bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS;
|
||||
uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot;
|
||||
bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) &&
|
||||
CurAddressState->OutSec->Type == SHT_NOBITS;
|
||||
uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot;
|
||||
Start = alignTo(Start, Align);
|
||||
uint64_t End = Start + Size;
|
||||
|
||||
if (IsTbss)
|
||||
ThreadBssOffset = End - Dot;
|
||||
CurAddressState->ThreadBssOffset = End - Dot;
|
||||
else
|
||||
Dot = End;
|
||||
return End;
|
||||
@ -524,40 +538,43 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
|
||||
|
||||
void LinkerScript::output(InputSection *S) {
|
||||
uint64_t Pos = advance(S->getSize(), S->Alignment);
|
||||
S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr;
|
||||
S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr;
|
||||
|
||||
// Update output section size after adding each section. This is so that
|
||||
// SIZEOF works correctly in the case below:
|
||||
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
|
||||
CurOutSec->Size = Pos - CurOutSec->Addr;
|
||||
CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr;
|
||||
|
||||
// If there is a memory region associated with this input section, then
|
||||
// place the section in that region and update the region index.
|
||||
if (CurMemRegion) {
|
||||
CurMemRegion->Offset += CurOutSec->Size;
|
||||
uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin;
|
||||
if (CurSize > CurMemRegion->Length) {
|
||||
uint64_t OverflowAmt = CurSize - CurMemRegion->Length;
|
||||
error("section '" + CurOutSec->Name + "' will not fit in region '" +
|
||||
CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) +
|
||||
" bytes");
|
||||
if (CurAddressState->MemRegion) {
|
||||
uint64_t &CurOffset =
|
||||
CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
|
||||
CurOffset += CurAddressState->OutSec->Size;
|
||||
uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin;
|
||||
if (CurSize > CurAddressState->MemRegion->Length) {
|
||||
uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length;
|
||||
error("section '" + CurAddressState->OutSec->Name +
|
||||
"' will not fit in region '" + CurAddressState->MemRegion->Name +
|
||||
"': overflowed by " + Twine(OverflowAmt) + " bytes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerScript::switchTo(OutputSection *Sec) {
|
||||
if (CurOutSec == Sec)
|
||||
if (CurAddressState->OutSec == Sec)
|
||||
return;
|
||||
|
||||
CurOutSec = Sec;
|
||||
CurOutSec->Addr = advance(0, CurOutSec->Alignment);
|
||||
CurAddressState->OutSec = Sec;
|
||||
CurAddressState->OutSec->Addr =
|
||||
advance(0, CurAddressState->OutSec->Alignment);
|
||||
|
||||
// If neither AT nor AT> is specified for an allocatable section, the linker
|
||||
// will set the LMA such that the difference between VMA and LMA for the
|
||||
// section is the same as the preceding output section in the same region
|
||||
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
|
||||
if (LMAOffset)
|
||||
CurOutSec->LMAOffset = LMAOffset();
|
||||
if (CurAddressState->LMAOffset)
|
||||
CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset();
|
||||
}
|
||||
|
||||
void LinkerScript::process(BaseCommand &Base) {
|
||||
@ -569,9 +586,9 @@ void LinkerScript::process(BaseCommand &Base) {
|
||||
|
||||
// Handle BYTE(), SHORT(), LONG(), or QUAD().
|
||||
if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) {
|
||||
Cmd->Offset = Dot - CurOutSec->Addr;
|
||||
Cmd->Offset = Dot - CurAddressState->OutSec->Addr;
|
||||
Dot += Cmd->Size;
|
||||
CurOutSec->Size = Dot - CurOutSec->Addr;
|
||||
CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -596,7 +613,7 @@ void LinkerScript::process(BaseCommand &Base) {
|
||||
|
||||
if (!Sec->Live)
|
||||
continue;
|
||||
assert(CurOutSec == Sec->getParent());
|
||||
assert(CurAddressState->OutSec == Sec->getParent());
|
||||
output(Sec);
|
||||
}
|
||||
}
|
||||
@ -649,17 +666,17 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
|
||||
|
||||
if (Cmd->LMAExpr) {
|
||||
uint64_t D = Dot;
|
||||
LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
|
||||
CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
|
||||
}
|
||||
|
||||
CurMemRegion = Cmd->MemRegion;
|
||||
if (CurMemRegion)
|
||||
Dot = CurMemRegion->Offset;
|
||||
CurAddressState->MemRegion = Cmd->MemRegion;
|
||||
if (CurAddressState->MemRegion)
|
||||
Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
|
||||
switchTo(Sec);
|
||||
|
||||
// We do not support custom layout for compressed debug sectons.
|
||||
// At this point we already know their size and have compressed content.
|
||||
if (CurOutSec->Flags & SHF_COMPRESSED)
|
||||
if (CurAddressState->OutSec->Flags & SHF_COMPRESSED)
|
||||
return;
|
||||
|
||||
for (BaseCommand *C : Cmd->Commands)
|
||||
@ -746,30 +763,20 @@ void LinkerScript::adjustSectionsAfterSorting() {
|
||||
if (!Cmd)
|
||||
continue;
|
||||
|
||||
if (Cmd->Phdrs.empty())
|
||||
Cmd->Phdrs = DefPhdrs;
|
||||
else
|
||||
if (Cmd->Phdrs.empty()) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
// To match the bfd linker script behaviour, only propagate program
|
||||
// headers to sections that are allocated.
|
||||
if (Sec && (Sec->Flags & SHF_ALLOC))
|
||||
Cmd->Phdrs = DefPhdrs;
|
||||
} else {
|
||||
DefPhdrs = Cmd->Phdrs;
|
||||
}
|
||||
}
|
||||
|
||||
removeEmptyCommands();
|
||||
}
|
||||
|
||||
void LinkerScript::createOrphanCommands() {
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
if (Sec->SectionIndex != INT_MAX)
|
||||
continue;
|
||||
OutputSectionCommand *Cmd =
|
||||
createOutputSectionCommand(Sec->Name, "<internal>");
|
||||
Cmd->Sec = Sec;
|
||||
SecToCommand[Sec] = Cmd;
|
||||
auto *ISD = make<InputSectionDescription>("");
|
||||
ISD->Sections = Sec->Sections;
|
||||
Cmd->Commands.push_back(ISD);
|
||||
Opt.Commands.push_back(Cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerScript::processNonSectionCommands() {
|
||||
for (BaseCommand *Base : Opt.Commands) {
|
||||
if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
|
||||
@ -779,22 +786,25 @@ void LinkerScript::processNonSectionCommands() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
allocateHeaders(std::vector<PhdrEntry> &Phdrs,
|
||||
ArrayRef<OutputSectionCommand *> OutputSectionCommands,
|
||||
uint64_t Min) {
|
||||
auto FirstPTLoad =
|
||||
std::find_if(Phdrs.begin(), Phdrs.end(),
|
||||
[](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
|
||||
void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) {
|
||||
uint64_t Min = std::numeric_limits<uint64_t>::max();
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->Flags & SHF_ALLOC)
|
||||
Min = std::min<uint64_t>(Min, Sec->Addr);
|
||||
}
|
||||
|
||||
auto FirstPTLoad = llvm::find_if(
|
||||
Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
|
||||
if (FirstPTLoad == Phdrs.end())
|
||||
return false;
|
||||
return;
|
||||
|
||||
uint64_t HeaderSize = getHeaderSize();
|
||||
if (HeaderSize <= Min || Script->hasPhdrsCommands()) {
|
||||
Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
|
||||
Out::ElfHeader->Addr = Min;
|
||||
Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(FirstPTLoad->First == Out::ElfHeader);
|
||||
@ -817,17 +827,28 @@ allocateHeaders(std::vector<PhdrEntry> &Phdrs,
|
||||
Phdrs.erase(FirstPTLoad);
|
||||
}
|
||||
|
||||
auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) {
|
||||
return E.p_type == PT_PHDR;
|
||||
});
|
||||
auto PhdrI = llvm::find_if(
|
||||
Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; });
|
||||
if (PhdrI != Phdrs.end())
|
||||
Phdrs.erase(PhdrI);
|
||||
return false;
|
||||
}
|
||||
|
||||
void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
|
||||
LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) {
|
||||
for (auto &MRI : Opt.MemoryRegions) {
|
||||
const MemoryRegion *MR = &MRI.second;
|
||||
MemRegionOffset[MR] = MR->Origin;
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerScript::assignAddresses() {
|
||||
// Assign addresses as instructed by linker script SECTIONS sub-commands.
|
||||
Dot = 0;
|
||||
auto State = make_unique<AddressState>(Opt);
|
||||
// CurAddressState captures the local AddressState and makes it accessible
|
||||
// deliberately. This is needed as there are some cases where we cannot just
|
||||
// thread the current state through to a lambda function created by the
|
||||
// script parser.
|
||||
CurAddressState = State.get();
|
||||
ErrorOnMissingSection = true;
|
||||
switchTo(Aether);
|
||||
|
||||
@ -845,15 +866,7 @@ void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
|
||||
auto *Cmd = cast<OutputSectionCommand>(Base);
|
||||
assignOffsets(Cmd);
|
||||
}
|
||||
|
||||
uint64_t MinVA = std::numeric_limits<uint64_t>::max();
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->Flags & SHF_ALLOC)
|
||||
MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
|
||||
}
|
||||
|
||||
allocateHeaders(Phdrs, OutputSectionCommands, MinVA);
|
||||
CurAddressState = nullptr;
|
||||
}
|
||||
|
||||
// Creates program headers as instructed by PHDRS linker script command.
|
||||
@ -879,12 +892,9 @@ std::vector<PhdrEntry> LinkerScript::createPhdrs() {
|
||||
|
||||
// Add output sections to program headers.
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (!(Sec->Flags & SHF_ALLOC))
|
||||
break;
|
||||
|
||||
// Assign headers specified by linker script
|
||||
for (size_t Id : getPhdrIndices(Sec)) {
|
||||
for (size_t Id : getPhdrIndices(Cmd)) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
Ret[Id].add(Sec);
|
||||
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
|
||||
Ret[Id].p_flags |= Sec->getPhdrFlags();
|
||||
@ -911,6 +921,92 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
|
||||
return I->second;
|
||||
}
|
||||
|
||||
void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) {
|
||||
typedef std::pair<unsigned, InputSection *> Pair;
|
||||
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
|
||||
|
||||
std::vector<Pair> V;
|
||||
assert(Commands.size() == 1);
|
||||
auto *ISD = cast<InputSectionDescription>(Commands[0]);
|
||||
for (InputSection *S : ISD->Sections)
|
||||
V.push_back({Order(S), S});
|
||||
std::stable_sort(V.begin(), V.end(), Comp);
|
||||
ISD->Sections.clear();
|
||||
for (Pair &P : V)
|
||||
ISD->Sections.push_back(P.second);
|
||||
}
|
||||
|
||||
// Returns true if S matches /Filename.?\.o$/.
|
||||
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
|
||||
if (!S.endswith(".o"))
|
||||
return false;
|
||||
S = S.drop_back(2);
|
||||
if (S.endswith(Filename))
|
||||
return true;
|
||||
return !S.empty() && S.drop_back().endswith(Filename);
|
||||
}
|
||||
|
||||
static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
|
||||
static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
|
||||
|
||||
// .ctors and .dtors are sorted by this priority from highest to lowest.
|
||||
//
|
||||
// 1. The section was contained in crtbegin (crtbegin contains
|
||||
// some sentinel value in its .ctors and .dtors so that the runtime
|
||||
// can find the beginning of the sections.)
|
||||
//
|
||||
// 2. The section has an optional priority value in the form of ".ctors.N"
|
||||
// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
|
||||
// they are compared as string rather than number.
|
||||
//
|
||||
// 3. The section is just ".ctors" or ".dtors".
|
||||
//
|
||||
// 4. The section was contained in crtend, which contains an end marker.
|
||||
//
|
||||
// In an ideal world, we don't need this function because .init_array and
|
||||
// .ctors are duplicate features (and .init_array is newer.) However, there
|
||||
// are too many real-world use cases of .ctors, so we had no choice to
|
||||
// support that with this rather ad-hoc semantics.
|
||||
static bool compCtors(const InputSection *A, const InputSection *B) {
|
||||
bool BeginA = isCrtbegin(A->File->getName());
|
||||
bool BeginB = isCrtbegin(B->File->getName());
|
||||
if (BeginA != BeginB)
|
||||
return BeginA;
|
||||
bool EndA = isCrtend(A->File->getName());
|
||||
bool EndB = isCrtend(B->File->getName());
|
||||
if (EndA != EndB)
|
||||
return EndB;
|
||||
StringRef X = A->Name;
|
||||
StringRef Y = B->Name;
|
||||
assert(X.startswith(".ctors") || X.startswith(".dtors"));
|
||||
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
|
||||
X = X.substr(6);
|
||||
Y = Y.substr(6);
|
||||
if (X.empty() && Y.empty())
|
||||
return false;
|
||||
return X < Y;
|
||||
}
|
||||
|
||||
// Sorts input sections by the special rules for .ctors and .dtors.
|
||||
// Unfortunately, the rules are different from the one for .{init,fini}_array.
|
||||
// Read the comment above.
|
||||
void OutputSectionCommand::sortCtorsDtors() {
|
||||
assert(Commands.size() == 1);
|
||||
auto *ISD = cast<InputSectionDescription>(Commands[0]);
|
||||
std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
|
||||
}
|
||||
|
||||
// Sorts input sections by section name suffixes, so that .foo.N comes
|
||||
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
|
||||
// We want to keep the original order if the priorities are the same
|
||||
// because the compiler keeps the original initialization order in a
|
||||
// translation unit and we need to respect that.
|
||||
// For more detail, read the section of the GCC's manual about init_priority.
|
||||
void OutputSectionCommand::sortInitFini() {
|
||||
// Sort sections by priority.
|
||||
sort([](InputSectionBase *S) { return getPriority(S->Name); });
|
||||
}
|
||||
|
||||
uint32_t OutputSectionCommand::getFiller() {
|
||||
if (Filler)
|
||||
return *Filler;
|
||||
@ -1085,16 +1181,9 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
|
||||
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
|
||||
}
|
||||
|
||||
bool LinkerScript::hasLMA(OutputSection *Sec) {
|
||||
if (OutputSectionCommand *Cmd = getCmd(Sec))
|
||||
if (Cmd->LMAExpr)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
|
||||
if (S == ".")
|
||||
return {CurOutSec, Dot - CurOutSec->Addr, Loc};
|
||||
return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc};
|
||||
if (SymbolBody *B = findSymbol(S)) {
|
||||
if (auto *D = dyn_cast<DefinedRegular>(B))
|
||||
return {D->Section, D->Value, Loc};
|
||||
@ -1111,17 +1200,14 @@ static const size_t NoPhdr = -1;
|
||||
|
||||
// Returns indices of ELF headers containing specific section. Each index is a
|
||||
// zero based number of ELF header listed within PHDRS {} script block.
|
||||
std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Sec) {
|
||||
if (OutputSectionCommand *Cmd = getCmd(Sec)) {
|
||||
std::vector<size_t> Ret;
|
||||
for (StringRef PhdrName : Cmd->Phdrs) {
|
||||
size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
|
||||
if (Index != NoPhdr)
|
||||
Ret.push_back(Index);
|
||||
}
|
||||
return Ret;
|
||||
std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) {
|
||||
std::vector<size_t> Ret;
|
||||
for (StringRef PhdrName : Cmd->Phdrs) {
|
||||
size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
|
||||
if (Index != NoPhdr)
|
||||
Ret.push_back(Index);
|
||||
}
|
||||
return {};
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// Returns the index of the segment named PhdrName if found otherwise
|
||||
|
@ -110,7 +110,6 @@ struct MemoryRegion {
|
||||
std::string Name;
|
||||
uint64_t Origin;
|
||||
uint64_t Length;
|
||||
uint64_t Offset;
|
||||
uint32_t Flags;
|
||||
uint32_t NegFlags;
|
||||
};
|
||||
@ -140,6 +139,10 @@ struct OutputSectionCommand : BaseCommand {
|
||||
template <class ELFT> void writeTo(uint8_t *Buf);
|
||||
template <class ELFT> void maybeCompress();
|
||||
uint32_t getFiller();
|
||||
|
||||
void sort(std::function<int(InputSectionBase *S)> Order);
|
||||
void sortInitFini();
|
||||
void sortCtorsDtors();
|
||||
};
|
||||
|
||||
// This struct represents one section match pattern in SECTIONS() command.
|
||||
@ -222,6 +225,17 @@ struct ScriptConfiguration {
|
||||
};
|
||||
|
||||
class LinkerScript final {
|
||||
// Temporary state used in processCommands() and assignAddresses()
|
||||
// that must be reinitialized for each call to the above functions, and must
|
||||
// not be used outside of the scope of a call to the above functions.
|
||||
struct AddressState {
|
||||
uint64_t ThreadBssOffset = 0;
|
||||
OutputSection *OutSec = nullptr;
|
||||
MemoryRegion *MemRegion = nullptr;
|
||||
llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset;
|
||||
std::function<uint64_t()> LMAOffset;
|
||||
AddressState(const ScriptConfiguration &Opt);
|
||||
};
|
||||
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
|
||||
llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand;
|
||||
|
||||
@ -234,7 +248,7 @@ class LinkerScript final {
|
||||
std::vector<InputSectionBase *>
|
||||
createInputSectionList(OutputSectionCommand &Cmd);
|
||||
|
||||
std::vector<size_t> getPhdrIndices(OutputSection *Sec);
|
||||
std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd);
|
||||
size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
|
||||
|
||||
MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
|
||||
@ -244,14 +258,10 @@ class LinkerScript final {
|
||||
void output(InputSection *Sec);
|
||||
void process(BaseCommand &Base);
|
||||
|
||||
AddressState *CurAddressState = nullptr;
|
||||
OutputSection *Aether;
|
||||
|
||||
uint64_t Dot;
|
||||
uint64_t ThreadBssOffset = 0;
|
||||
|
||||
std::function<uint64_t()> LMAOffset;
|
||||
OutputSection *CurOutSec = nullptr;
|
||||
MemoryRegion *CurMemRegion = nullptr;
|
||||
|
||||
public:
|
||||
bool ErrorOnMissingSection = false;
|
||||
@ -276,13 +286,11 @@ class LinkerScript final {
|
||||
std::vector<PhdrEntry> createPhdrs();
|
||||
bool ignoreInterpSection();
|
||||
|
||||
bool hasLMA(OutputSection *Sec);
|
||||
bool shouldKeep(InputSectionBase *S);
|
||||
void assignOffsets(OutputSectionCommand *Cmd);
|
||||
void createOrphanCommands();
|
||||
void processNonSectionCommands();
|
||||
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
|
||||
|
||||
void assignAddresses();
|
||||
void allocateHeaders(std::vector<PhdrEntry> &Phdrs);
|
||||
void addSymbol(SymbolAssignment *Cmd);
|
||||
void processCommands(OutputSectionFactory &Factory);
|
||||
|
||||
|
@ -101,100 +101,6 @@ void OutputSection::addSection(InputSection *S) {
|
||||
this->Entsize = std::max(this->Entsize, S->Entsize);
|
||||
}
|
||||
|
||||
// This function is called after we sort input sections
|
||||
// and scan relocations to setup sections' offsets.
|
||||
void OutputSection::assignOffsets() {
|
||||
OutputSectionCommand *Cmd = Script->getCmd(this);
|
||||
uint64_t Off = 0;
|
||||
for (BaseCommand *Base : Cmd->Commands)
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
|
||||
for (InputSection *S : ISD->Sections)
|
||||
Off = updateOffset(Off, S);
|
||||
this->Size = Off;
|
||||
}
|
||||
|
||||
void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
|
||||
typedef std::pair<unsigned, InputSection *> Pair;
|
||||
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
|
||||
|
||||
std::vector<Pair> V;
|
||||
for (InputSection *S : Sections)
|
||||
V.push_back({Order(S), S});
|
||||
std::stable_sort(V.begin(), V.end(), Comp);
|
||||
Sections.clear();
|
||||
for (Pair &P : V)
|
||||
Sections.push_back(P.second);
|
||||
}
|
||||
|
||||
// Sorts input sections by section name suffixes, so that .foo.N comes
|
||||
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
|
||||
// We want to keep the original order if the priorities are the same
|
||||
// because the compiler keeps the original initialization order in a
|
||||
// translation unit and we need to respect that.
|
||||
// For more detail, read the section of the GCC's manual about init_priority.
|
||||
void OutputSection::sortInitFini() {
|
||||
// Sort sections by priority.
|
||||
sort([](InputSectionBase *S) { return getPriority(S->Name); });
|
||||
}
|
||||
|
||||
// Returns true if S matches /Filename.?\.o$/.
|
||||
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
|
||||
if (!S.endswith(".o"))
|
||||
return false;
|
||||
S = S.drop_back(2);
|
||||
if (S.endswith(Filename))
|
||||
return true;
|
||||
return !S.empty() && S.drop_back().endswith(Filename);
|
||||
}
|
||||
|
||||
static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
|
||||
static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
|
||||
|
||||
// .ctors and .dtors are sorted by this priority from highest to lowest.
|
||||
//
|
||||
// 1. The section was contained in crtbegin (crtbegin contains
|
||||
// some sentinel value in its .ctors and .dtors so that the runtime
|
||||
// can find the beginning of the sections.)
|
||||
//
|
||||
// 2. The section has an optional priority value in the form of ".ctors.N"
|
||||
// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
|
||||
// they are compared as string rather than number.
|
||||
//
|
||||
// 3. The section is just ".ctors" or ".dtors".
|
||||
//
|
||||
// 4. The section was contained in crtend, which contains an end marker.
|
||||
//
|
||||
// In an ideal world, we don't need this function because .init_array and
|
||||
// .ctors are duplicate features (and .init_array is newer.) However, there
|
||||
// are too many real-world use cases of .ctors, so we had no choice to
|
||||
// support that with this rather ad-hoc semantics.
|
||||
static bool compCtors(const InputSection *A, const InputSection *B) {
|
||||
bool BeginA = isCrtbegin(A->File->getName());
|
||||
bool BeginB = isCrtbegin(B->File->getName());
|
||||
if (BeginA != BeginB)
|
||||
return BeginA;
|
||||
bool EndA = isCrtend(A->File->getName());
|
||||
bool EndB = isCrtend(B->File->getName());
|
||||
if (EndA != EndB)
|
||||
return EndB;
|
||||
StringRef X = A->Name;
|
||||
StringRef Y = B->Name;
|
||||
assert(X.startswith(".ctors") || X.startswith(".dtors"));
|
||||
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
|
||||
X = X.substr(6);
|
||||
Y = Y.substr(6);
|
||||
if (X.empty() && Y.empty())
|
||||
return false;
|
||||
return X < Y;
|
||||
}
|
||||
|
||||
// Sorts input sections by the special rules for .ctors and .dtors.
|
||||
// Unfortunately, the rules are different from the one for .{init,fini}_array.
|
||||
// Read the comment above.
|
||||
void OutputSection::sortCtorsDtors() {
|
||||
std::stable_sort(Sections.begin(), Sections.end(), compCtors);
|
||||
}
|
||||
|
||||
static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
|
||||
// The ELF spec just says
|
||||
// ----------------------------------------------------------------
|
||||
@ -249,9 +155,7 @@ static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
|
||||
return SectionKey{OutsecName, Flags, Alignment};
|
||||
}
|
||||
|
||||
OutputSectionFactory::OutputSectionFactory(
|
||||
std::vector<OutputSection *> &OutputSections)
|
||||
: OutputSections(OutputSections) {}
|
||||
OutputSectionFactory::OutputSectionFactory() {}
|
||||
|
||||
static uint64_t getIncompatibleFlags(uint64_t Flags) {
|
||||
return Flags & (SHF_ALLOC | SHF_TLS);
|
||||
|
@ -80,10 +80,6 @@ class OutputSection final : public SectionBase {
|
||||
uint32_t ShName = 0;
|
||||
|
||||
void addSection(InputSection *S);
|
||||
void sort(std::function<int(InputSectionBase *S)> Order);
|
||||
void sortInitFini();
|
||||
void sortCtorsDtors();
|
||||
void assignOffsets();
|
||||
std::vector<InputSection *> Sections;
|
||||
|
||||
// Used for implementation of --compress-debug-sections option.
|
||||
@ -135,7 +131,7 @@ namespace elf {
|
||||
// linker scripts.
|
||||
class OutputSectionFactory {
|
||||
public:
|
||||
OutputSectionFactory(std::vector<OutputSection *> &OutputSections);
|
||||
OutputSectionFactory();
|
||||
~OutputSectionFactory();
|
||||
|
||||
void addInputSec(InputSectionBase *IS, StringRef OutsecName);
|
||||
@ -144,7 +140,6 @@ class OutputSectionFactory {
|
||||
|
||||
private:
|
||||
llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
|
||||
std::vector<OutputSection *> &OutputSections;
|
||||
};
|
||||
|
||||
uint64_t getHeaderSize();
|
||||
|
@ -557,9 +557,9 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type,
|
||||
// the refered symbol can be preemepted to refer to the executable.
|
||||
if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
|
||||
error("can't create dynamic relocation " + toString(Type) + " against " +
|
||||
(Body.getName().empty() ? "local symbol in readonly segment"
|
||||
(Body.getName().empty() ? "local symbol"
|
||||
: "symbol: " + toString(Body)) +
|
||||
getLocation<ELFT>(S, Body, RelOff));
|
||||
" in readonly segment" + getLocation<ELFT>(S, Body, RelOff));
|
||||
return Expr;
|
||||
}
|
||||
|
||||
@ -1049,10 +1049,17 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
|
||||
|
||||
std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
|
||||
uint32_t Type) {
|
||||
auto res = ThunkedSymbols.insert({&Body, nullptr});
|
||||
if (res.second)
|
||||
res.first->second = addThunk(Type, Body);
|
||||
return std::make_pair(res.first->second, res.second);
|
||||
auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()});
|
||||
if (!Res.second) {
|
||||
// Check existing Thunks for Body to see if they can be reused
|
||||
for (Thunk *ET : Res.first->second)
|
||||
if (ET->isCompatibleWith(Type))
|
||||
return std::make_pair(ET, false);
|
||||
}
|
||||
// No existing compatible Thunk in range, create a new one
|
||||
Thunk *T = addThunk(Type, Body);
|
||||
Res.first->second.push_back(T);
|
||||
return std::make_pair(T, true);
|
||||
}
|
||||
|
||||
// Call Fn on every executable InputSection accessed via the linker script
|
||||
@ -1066,13 +1073,12 @@ void ThunkCreator::forEachExecInputSection(
|
||||
OutputSection *OS = Cmd->Sec;
|
||||
if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
if (OutputSectionCommand *C = Script->getCmd(OS))
|
||||
for (BaseCommand *BC : C->Commands)
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
|
||||
CurTS = nullptr;
|
||||
for (InputSection* IS : ISD->Sections)
|
||||
Fn(OS, &ISD->Sections, IS);
|
||||
}
|
||||
for (BaseCommand *BC : Cmd->Commands)
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
|
||||
CurTS = nullptr;
|
||||
for (InputSection *IS : ISD->Sections)
|
||||
Fn(OS, &ISD->Sections, IS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,14 +144,17 @@ class ThunkCreator {
|
||||
std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
|
||||
ThunkSection *addThunkSection(OutputSection *OS,
|
||||
std::vector<InputSection *> *, uint64_t Off);
|
||||
// Track Symbols that already have a Thunk
|
||||
llvm::DenseMap<SymbolBody *, Thunk *> ThunkedSymbols;
|
||||
// Record all the available Thunks for a Symbol
|
||||
llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols;
|
||||
|
||||
// Find a Thunk from the Thunks symbol definition, we can use this to find
|
||||
// the Thunk from a relocation to the Thunks symbol definition.
|
||||
llvm::DenseMap<SymbolBody *, Thunk *> Thunks;
|
||||
|
||||
// Track InputSections that have a ThunkSection placed in front
|
||||
// Track InputSections that have an inline ThunkSection placed in front
|
||||
// an inline ThunkSection may have control fall through to the section below
|
||||
// so we need to make sure that there is only one of them.
|
||||
// The Mips LA25 Thunk is an example of an inline ThunkSection.
|
||||
llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
|
||||
|
||||
// All the ThunkSections that we have created, organised by OutputSection
|
||||
|
@ -1191,8 +1191,7 @@ void ScriptParser::readMemory() {
|
||||
if (It != Script->Opt.MemoryRegions.end())
|
||||
setError("region '" + Name + "' already defined");
|
||||
else
|
||||
Script->Opt.MemoryRegions[Name] = {Name, Origin, Length,
|
||||
Origin, Flags, NegFlags};
|
||||
Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +211,13 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
|
||||
// Find an existing symbol or create and insert a new one.
|
||||
template <class ELFT>
|
||||
std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
|
||||
// <name>@@<version> means the symbol is the default version. In that
|
||||
// case symbol <name> must exist and <name>@@<version> will be used to
|
||||
// resolve references to <name>.
|
||||
size_t Pos = Name.find("@@");
|
||||
if (Pos != StringRef::npos)
|
||||
Name = Name.take_front(Pos);
|
||||
|
||||
auto P = Symtab.insert(
|
||||
{CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
|
||||
SymIndex &V = P.first->second;
|
||||
@ -319,7 +326,7 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
|
||||
if (WasInserted)
|
||||
return 1;
|
||||
SymbolBody *Body = S->body();
|
||||
if (Body->isLazy() || !Body->isInCurrentDSO())
|
||||
if (!Body->isInCurrentDSO())
|
||||
return 1;
|
||||
if (Binding == STB_WEAK)
|
||||
return -1;
|
||||
@ -689,6 +696,12 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId
|
||||
|
||||
// Assign the version.
|
||||
for (SymbolBody *B : Syms) {
|
||||
// Skip symbols containing version info because symbol versions
|
||||
// specified by symbol names take precedence over version scripts.
|
||||
// See parseSymbolVersion().
|
||||
if (B->getName().find('@') != StringRef::npos)
|
||||
continue;
|
||||
|
||||
Symbol *Sym = B->symbol();
|
||||
if (Sym->InVersionScript)
|
||||
warn("duplicate symbol '" + Ver.Name + "' in version script");
|
||||
@ -702,47 +715,21 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
|
||||
uint16_t VersionId) {
|
||||
if (!Ver.HasWildcard)
|
||||
return;
|
||||
std::vector<SymbolBody *> Syms = findAllByVersion(Ver);
|
||||
|
||||
// Exact matching takes precendence over fuzzy matching,
|
||||
// so we set a version to a symbol only if no version has been assigned
|
||||
// to the symbol. This behavior is compatible with GNU.
|
||||
for (SymbolBody *B : Syms)
|
||||
for (SymbolBody *B : findAllByVersion(Ver))
|
||||
if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
|
||||
B->symbol()->VersionId = VersionId;
|
||||
}
|
||||
|
||||
static bool isDefaultVersion(SymbolBody *B) {
|
||||
return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos;
|
||||
}
|
||||
|
||||
// This function processes version scripts by updating VersionId
|
||||
// member of symbols.
|
||||
template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
|
||||
// Symbol themselves might know their versions because symbols
|
||||
// can contain versions in the form of <name>@<version>.
|
||||
// Let them parse and update their names to exclude version suffix.
|
||||
for (Symbol *Sym : SymVector) {
|
||||
SymbolBody *Body = Sym->body();
|
||||
bool IsDefault = isDefaultVersion(Body);
|
||||
Body->parseSymbolVersion();
|
||||
|
||||
if (!IsDefault)
|
||||
continue;
|
||||
|
||||
// <name>@@<version> means the symbol is the default version. If that's the
|
||||
// case, the symbol is not used only to resolve <name> of version <version>
|
||||
// but also undefined unversioned symbols with name <name>.
|
||||
SymbolBody *S = find(Body->getName());
|
||||
if (S && S->isUndefined())
|
||||
S->copy(Body);
|
||||
}
|
||||
|
||||
// Handle edge cases first.
|
||||
handleAnonymousVersion();
|
||||
|
||||
if (Config->VersionDefinitions.empty())
|
||||
return;
|
||||
|
||||
// Now we have version definitions, so we need to set version ids to symbols.
|
||||
// Each version definition has a glob pattern, and all symbols that match
|
||||
@ -761,6 +748,12 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
|
||||
for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
|
||||
for (SymbolVersion &Ver : V.Globals)
|
||||
assignWildcardVersion(Ver, V.Id);
|
||||
|
||||
// Symbol themselves might know their versions because symbols
|
||||
// can contain versions in the form of <name>@<version>.
|
||||
// Let them parse and update their names to exclude version suffix.
|
||||
for (Symbol *Sym : SymVector)
|
||||
Sym->body()->parseSymbolVersion();
|
||||
}
|
||||
|
||||
template class elf::SymbolTable<ELF32LE>;
|
||||
|
@ -159,19 +159,12 @@ bool SymbolBody::isPreemptible() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overwrites all attributes except symbol name with Other's so that
|
||||
// this symbol becomes an alias to Other. This is useful for handling
|
||||
// some options such as --wrap.
|
||||
//
|
||||
// The reason why we want to keep the symbol name is because, if we
|
||||
// copy symbol names, we'll end up having symbol tables in resulting
|
||||
// executables or DSOs containing two or more identical symbols, which
|
||||
// is just inconvenient.
|
||||
// Overwrites all attributes with Other's so that this symbol becomes
|
||||
// an alias to Other. This is useful for handling some options such as
|
||||
// --wrap.
|
||||
void SymbolBody::copy(SymbolBody *Other) {
|
||||
StringRef S = Name;
|
||||
memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
|
||||
sizeof(Symbol::Body));
|
||||
Name = S;
|
||||
}
|
||||
|
||||
uint64_t SymbolBody::getVA(int64_t Addend) const {
|
||||
@ -272,7 +265,12 @@ void SymbolBody::parseSymbolVersion() {
|
||||
}
|
||||
|
||||
// It is an error if the specified version is not defined.
|
||||
error(toString(File) + ": symbol " + S + " has undefined version " + Verstr);
|
||||
// Usually version script is not provided when linking executable,
|
||||
// but we may still want to override a versioned symbol from DSO,
|
||||
// so we do not report error in this case.
|
||||
if (Config->Shared)
|
||||
error(toString(File) + ": symbol " + S + " has undefined version " +
|
||||
Verstr);
|
||||
}
|
||||
|
||||
Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
|
||||
|
@ -65,7 +65,9 @@ class SymbolBody {
|
||||
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
|
||||
}
|
||||
bool isShared() const { return SymbolKind == SharedKind; }
|
||||
bool isInCurrentDSO() const { return !isUndefined() && !isShared(); }
|
||||
bool isInCurrentDSO() const {
|
||||
return !isUndefined() && !isShared() && !isLazy();
|
||||
}
|
||||
bool isLocal() const { return IsLocal; }
|
||||
bool isPreemptible() const;
|
||||
StringRef getName() const { return Name; }
|
||||
@ -218,7 +220,7 @@ class SharedSymbol : public Defined {
|
||||
Verdef(Verdef), ElfSym(ElfSym) {
|
||||
// IFuncs defined in DSOs are treated as functions by the static linker.
|
||||
if (isGnuIFunc())
|
||||
Type = llvm::ELF::STT_FUNC;
|
||||
this->Type = llvm::ELF::STT_FUNC;
|
||||
this->File = File;
|
||||
}
|
||||
|
||||
|
@ -1071,10 +1071,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
return; // Already finalized.
|
||||
|
||||
this->Link = InX::DynStrTab->getParent()->SectionIndex;
|
||||
if (In<ELFT>::RelaDyn->getParent()->Size > 0) {
|
||||
if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) {
|
||||
bool IsRela = Config->IsRela;
|
||||
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
|
||||
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent()->Size});
|
||||
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(),
|
||||
Entry::SecSize});
|
||||
add({IsRela ? DT_RELAENT : DT_RELENT,
|
||||
uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
|
||||
|
||||
@ -1087,9 +1088,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
|
||||
}
|
||||
}
|
||||
if (In<ELFT>::RelaPlt->getParent()->Size > 0) {
|
||||
if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) {
|
||||
add({DT_JMPREL, In<ELFT>::RelaPlt});
|
||||
add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size});
|
||||
add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize});
|
||||
switch (Config->EMachine) {
|
||||
case EM_MIPS:
|
||||
add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt});
|
||||
@ -1699,9 +1700,9 @@ unsigned PltSection::getPltRelocOff() const {
|
||||
return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
|
||||
}
|
||||
|
||||
GdbIndexSection::GdbIndexSection()
|
||||
GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks)
|
||||
: SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"),
|
||||
StringPool(llvm::StringTableBuilder::ELF) {}
|
||||
StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {}
|
||||
|
||||
// Iterative hash function for symbol's name is described in .gdb_index format
|
||||
// specification. Note that we use one for version 5 to 7 here, it is different
|
||||
@ -1713,11 +1714,10 @@ static uint32_t hash(StringRef Str) {
|
||||
return R;
|
||||
}
|
||||
|
||||
static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf,
|
||||
InputSection *Sec) {
|
||||
static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) {
|
||||
std::vector<CompilationUnitEntry> Ret;
|
||||
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
|
||||
Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
|
||||
Ret.push_back({CU->getOffset(), CU->getLength() + 4});
|
||||
return Ret;
|
||||
}
|
||||
|
||||
@ -1764,19 +1764,15 @@ static std::vector<InputSection *> getDebugInfoSections() {
|
||||
std::vector<InputSection *> Ret;
|
||||
for (InputSectionBase *S : InputSections)
|
||||
if (InputSection *IS = dyn_cast<InputSection>(S))
|
||||
if (IS->getParent() && IS->Name == ".debug_info")
|
||||
if (IS->Name == ".debug_info")
|
||||
Ret.push_back(IS);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
void GdbIndexSection::buildIndex() {
|
||||
std::vector<InputSection *> V = getDebugInfoSections();
|
||||
if (V.empty())
|
||||
if (Chunks.empty())
|
||||
return;
|
||||
|
||||
for (InputSection *Sec : V)
|
||||
Chunks.push_back(readDwarf(Sec));
|
||||
|
||||
uint32_t CuId = 0;
|
||||
for (GdbIndexChunk &D : Chunks) {
|
||||
for (AddressEntry &E : D.AddressArea)
|
||||
@ -1802,23 +1798,33 @@ void GdbIndexSection::buildIndex() {
|
||||
}
|
||||
}
|
||||
|
||||
GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) {
|
||||
Expected<std::unique_ptr<object::ObjectFile>> Obj =
|
||||
object::ObjectFile::createObjectFile(Sec->File->MB);
|
||||
if (!Obj) {
|
||||
error(toString(Sec->File) + ": error creating DWARF context");
|
||||
return {};
|
||||
}
|
||||
|
||||
DWARFContextInMemory Dwarf(*Obj.get());
|
||||
|
||||
static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) {
|
||||
GdbIndexChunk Ret;
|
||||
Ret.CompilationUnits = readCuList(Dwarf, Sec);
|
||||
Ret.DebugInfoSec = Sec;
|
||||
Ret.CompilationUnits = readCuList(Dwarf);
|
||||
Ret.AddressArea = readAddressArea(Dwarf, Sec);
|
||||
Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
|
||||
std::vector<GdbIndexChunk> Chunks;
|
||||
for (InputSection *Sec : getDebugInfoSections()) {
|
||||
InputFile *F = Sec->File;
|
||||
std::error_code EC;
|
||||
ELFObjectFile<ELFT> Obj(F->MB, EC);
|
||||
if (EC)
|
||||
fatal(EC.message());
|
||||
DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) {
|
||||
error(toString(F) + ": error parsing DWARF data:\n>>> " +
|
||||
toString(std::move(E)));
|
||||
return ErrorPolicy::Continue;
|
||||
});
|
||||
Chunks.push_back(readDwarf(Dwarf, Sec));
|
||||
}
|
||||
return make<GdbIndexSection>(std::move(Chunks));
|
||||
}
|
||||
|
||||
static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
|
||||
size_t Ret = 0;
|
||||
for (GdbIndexChunk &D : C)
|
||||
@ -1876,7 +1882,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
|
||||
// Write the CU list.
|
||||
for (GdbIndexChunk &D : Chunks) {
|
||||
for (CompilationUnitEntry &Cu : D.CompilationUnits) {
|
||||
write64le(Buf, Cu.CuOffset);
|
||||
write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
|
||||
write64le(Buf + 8, Cu.CuLength);
|
||||
Buf += 16;
|
||||
}
|
||||
@ -2345,6 +2351,11 @@ StringTableSection *InX::ShStrTab;
|
||||
StringTableSection *InX::StrTab;
|
||||
SymbolTableBaseSection *InX::SymTab;
|
||||
|
||||
template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
|
||||
template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
|
||||
template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
|
||||
template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
|
||||
|
||||
template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym);
|
||||
template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym);
|
||||
template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym);
|
||||
|
@ -503,7 +503,7 @@ class GdbIndexSection final : public SyntheticSection {
|
||||
const unsigned SymTabEntrySize = 2 * OffsetTypeSize;
|
||||
|
||||
public:
|
||||
GdbIndexSection();
|
||||
GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks);
|
||||
void finalizeContents() override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
size_t getSize() const override;
|
||||
@ -524,7 +524,6 @@ class GdbIndexSection final : public SyntheticSection {
|
||||
std::vector<GdbIndexChunk> Chunks;
|
||||
|
||||
private:
|
||||
GdbIndexChunk readDwarf(InputSection *Sec);
|
||||
void buildIndex();
|
||||
|
||||
uint32_t CuTypesOffset;
|
||||
@ -538,6 +537,8 @@ class GdbIndexSection final : public SyntheticSection {
|
||||
bool Finalized = false;
|
||||
};
|
||||
|
||||
template <class ELFT> GdbIndexSection *createGdbIndex();
|
||||
|
||||
// --eh-frame-hdr option tells linker to construct a header for all the
|
||||
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
|
||||
// and also to a PT_GNU_EH_FRAME segment.
|
||||
|
@ -57,6 +57,7 @@ class ARMV7ABSLongThunk final : public Thunk {
|
||||
uint32_t size() const override { return 12; }
|
||||
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
|
||||
void addSymbols(ThunkSection &IS) override;
|
||||
bool isCompatibleWith(uint32_t RelocType) const override;
|
||||
};
|
||||
|
||||
class ARMV7PILongThunk final : public Thunk {
|
||||
@ -66,28 +67,31 @@ class ARMV7PILongThunk final : public Thunk {
|
||||
uint32_t size() const override { return 16; }
|
||||
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
|
||||
void addSymbols(ThunkSection &IS) override;
|
||||
bool isCompatibleWith(uint32_t RelocType) const override;
|
||||
};
|
||||
|
||||
class ThumbV7ABSLongThunk final : public Thunk {
|
||||
public:
|
||||
ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {
|
||||
this->alignment = 2;
|
||||
alignment = 2;
|
||||
}
|
||||
|
||||
uint32_t size() const override { return 10; }
|
||||
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
|
||||
void addSymbols(ThunkSection &IS) override;
|
||||
bool isCompatibleWith(uint32_t RelocType) const override;
|
||||
};
|
||||
|
||||
class ThumbV7PILongThunk final : public Thunk {
|
||||
public:
|
||||
ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {
|
||||
this->alignment = 2;
|
||||
alignment = 2;
|
||||
}
|
||||
|
||||
uint32_t size() const override { return 12; }
|
||||
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
|
||||
void addSymbols(ThunkSection &IS) override;
|
||||
bool isCompatibleWith(uint32_t RelocType) const override;
|
||||
};
|
||||
|
||||
// MIPS LA25 thunk
|
||||
@ -128,6 +132,11 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
|
||||
addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
|
||||
}
|
||||
|
||||
bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
|
||||
// Thumb branch relocations can't use BLX
|
||||
return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
|
||||
}
|
||||
|
||||
void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
|
||||
const uint8_t Data[] = {
|
||||
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
|
||||
@ -147,6 +156,12 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
|
||||
addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
|
||||
}
|
||||
|
||||
bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
|
||||
// ARM branch relocations can't use BLX
|
||||
return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
|
||||
RelocType != R_ARM_PLT32;
|
||||
}
|
||||
|
||||
void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
|
||||
const uint8_t Data[] = {
|
||||
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
|
||||
@ -168,6 +183,11 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
|
||||
addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
|
||||
}
|
||||
|
||||
bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
|
||||
// Thumb branch relocations can't use BLX
|
||||
return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
|
||||
}
|
||||
|
||||
void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
|
||||
const uint8_t Data[] = {
|
||||
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
|
||||
@ -189,9 +209,15 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
|
||||
addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
|
||||
}
|
||||
|
||||
bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
|
||||
// ARM branch relocations can't use BLX
|
||||
return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
|
||||
RelocType != R_ARM_PLT32;
|
||||
}
|
||||
|
||||
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
|
||||
void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
|
||||
uint64_t S = this->Destination.getVA();
|
||||
uint64_t S = Destination.getVA();
|
||||
write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func)
|
||||
write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func
|
||||
write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func)
|
||||
|
@ -41,6 +41,10 @@ class Thunk {
|
||||
// a branch and fall through to the first Symbol in the Target.
|
||||
virtual InputSection *getTargetInputSection() const { return nullptr; }
|
||||
|
||||
// To reuse a Thunk the caller as identified by the RelocType must be
|
||||
// compatible with it.
|
||||
virtual bool isCompatibleWith(uint32_t RelocType) const { return true; }
|
||||
|
||||
// The alignment requirement for this Thunk, defaults to the size of the
|
||||
// typical code section alignment.
|
||||
const SymbolBody &Destination;
|
||||
|
167
ELF/Writer.cpp
167
ELF/Writer.cpp
@ -73,13 +73,12 @@ template <class ELFT> class Writer {
|
||||
|
||||
std::unique_ptr<FileOutputBuffer> Buffer;
|
||||
|
||||
OutputSectionFactory Factory{OutputSections};
|
||||
OutputSectionFactory Factory;
|
||||
|
||||
void addRelIpltSymbols();
|
||||
void addStartEndSymbols();
|
||||
void addStartStopSymbols(OutputSection *Sec);
|
||||
uint64_t getEntryAddr();
|
||||
OutputSection *findSection(StringRef Name);
|
||||
OutputSection *findSectionInScript(StringRef Name);
|
||||
OutputSectionCommand *findSectionCommand(StringRef Name);
|
||||
|
||||
@ -152,10 +151,6 @@ template <class ELFT> static void combineEhFrameSections() {
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::clearOutputSections() {
|
||||
if (Script->Opt.HasSections)
|
||||
Script->createOrphanCommands();
|
||||
else
|
||||
Script->fabricateDefaultCommands();
|
||||
// Clear the OutputSections to make sure it is not used anymore. Any
|
||||
// code from this point on should be using the linker script
|
||||
// commands.
|
||||
@ -190,9 +185,10 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||
// output sections by default rules. We still need to give the
|
||||
// linker script a chance to run, because it might contain
|
||||
// non-SECTIONS commands such as ASSERT.
|
||||
createSections();
|
||||
Script->processCommands(Factory);
|
||||
createSections();
|
||||
}
|
||||
clearOutputSections();
|
||||
|
||||
if (Config->Discard != DiscardPolicy::All)
|
||||
copyLocalSymbols();
|
||||
@ -218,7 +214,8 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||
OutputSectionCommands.begin(), OutputSectionCommands.end(),
|
||||
[](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
|
||||
|
||||
Script->assignAddresses(Phdrs);
|
||||
Script->assignAddresses();
|
||||
Script->allocateHeaders(Phdrs);
|
||||
|
||||
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
|
||||
// 0 sized region. This has to be done late since only after assignAddresses
|
||||
@ -383,7 +380,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
Add(InX::IgotPlt);
|
||||
|
||||
if (Config->GdbIndex) {
|
||||
InX::GdbIndex = make<GdbIndexSection>();
|
||||
InX::GdbIndex = createGdbIndex<ELFT>();
|
||||
Add(InX::GdbIndex);
|
||||
}
|
||||
|
||||
@ -499,11 +496,18 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
||||
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
|
||||
// Create one STT_SECTION symbol for each output section we might
|
||||
// have a relocation with.
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
if (Sec->Sections.empty())
|
||||
for (BaseCommand *Base : Script->Opt.Commands) {
|
||||
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
|
||||
if (!Cmd)
|
||||
continue;
|
||||
|
||||
InputSection *IS = Sec->Sections[0];
|
||||
auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) {
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
|
||||
return !ISD->Sections.empty();
|
||||
return false;
|
||||
});
|
||||
if (I == Cmd->Commands.end())
|
||||
continue;
|
||||
InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
|
||||
if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL ||
|
||||
IS->Type == SHT_RELA)
|
||||
continue;
|
||||
@ -864,20 +868,19 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
|
||||
|
||||
// Sort input sections by section name suffixes for
|
||||
// __attribute__((init_priority(N))).
|
||||
static void sortInitFini(OutputSection *S) {
|
||||
if (S)
|
||||
reinterpret_cast<OutputSection *>(S)->sortInitFini();
|
||||
static void sortInitFini(OutputSectionCommand *Cmd) {
|
||||
if (Cmd)
|
||||
Cmd->sortInitFini();
|
||||
}
|
||||
|
||||
// Sort input sections by the special rule for .ctors and .dtors.
|
||||
static void sortCtorsDtors(OutputSection *S) {
|
||||
if (S)
|
||||
reinterpret_cast<OutputSection *>(S)->sortCtorsDtors();
|
||||
static void sortCtorsDtors(OutputSectionCommand *Cmd) {
|
||||
if (Cmd)
|
||||
Cmd->sortCtorsDtors();
|
||||
}
|
||||
|
||||
// Sort input sections using the list provided by --symbol-ordering-file.
|
||||
template <class ELFT>
|
||||
static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) {
|
||||
template <class ELFT> static void sortBySymbolsOrder() {
|
||||
if (Config->SymbolOrderingFile.empty())
|
||||
return;
|
||||
|
||||
@ -902,9 +905,9 @@ static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) {
|
||||
}
|
||||
|
||||
// Sort sections by priority.
|
||||
for (OutputSection *Base : OutputSections)
|
||||
if (auto *Sec = dyn_cast<OutputSection>(Base))
|
||||
Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
|
||||
for (BaseCommand *Base : Script->Opt.Commands)
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
|
||||
Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -934,11 +937,12 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
||||
if (IS)
|
||||
Factory.addInputSec(IS, getOutputSectionName(IS->Name));
|
||||
|
||||
sortBySymbolsOrder<ELFT>(OutputSections);
|
||||
sortInitFini(findSection(".init_array"));
|
||||
sortInitFini(findSection(".fini_array"));
|
||||
sortCtorsDtors(findSection(".ctors"));
|
||||
sortCtorsDtors(findSection(".dtors"));
|
||||
Script->fabricateDefaultCommands();
|
||||
sortBySymbolsOrder<ELFT>();
|
||||
sortInitFini(findSectionCommand(".init_array"));
|
||||
sortInitFini(findSectionCommand(".fini_array"));
|
||||
sortCtorsDtors(findSectionCommand(".ctors"));
|
||||
sortCtorsDtors(findSectionCommand(".dtors"));
|
||||
}
|
||||
|
||||
// We want to find how similar two ranks are.
|
||||
@ -1132,7 +1136,7 @@ static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
|
||||
// to make them visible from linkescript side. But not all sections are always
|
||||
// required to be in output. For example we don't need dynamic section content
|
||||
// sometimes. This function filters out such unused sections from the output.
|
||||
static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
|
||||
static void removeUnusedSyntheticSections() {
|
||||
// All input synthetic sections that can be empty are placed after
|
||||
// all regular ones. We iterate over them all and exit at first
|
||||
// non-synthetic.
|
||||
@ -1145,29 +1149,53 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
|
||||
continue;
|
||||
if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable)
|
||||
continue;
|
||||
OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS));
|
||||
SS->Live = false;
|
||||
|
||||
OutputSectionCommand *Cmd = Script->getCmd(OS);
|
||||
std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end();
|
||||
for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) {
|
||||
BaseCommand *B = *I;
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
|
||||
auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS);
|
||||
if (P != ISD->Sections.end())
|
||||
ISD->Sections.erase(P);
|
||||
if (ISD->Sections.empty())
|
||||
Empty = I;
|
||||
}
|
||||
}
|
||||
if (Empty != Cmd->Commands.end())
|
||||
Cmd->Commands.erase(Empty);
|
||||
|
||||
// If there are no other sections in the output section, remove it from the
|
||||
// output.
|
||||
if (OS->Sections.empty())
|
||||
V.erase(std::find(V.begin(), V.end(), OS));
|
||||
if (Cmd->Commands.empty()) {
|
||||
// Also remove script commands matching the output section.
|
||||
auto &Cmds = Script->Opt.Commands;
|
||||
auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) {
|
||||
if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd))
|
||||
return OSCmd->Sec == OS;
|
||||
return false;
|
||||
});
|
||||
Cmds.erase(I, Cmds.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create output section objects and add them to OutputSections.
|
||||
template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
Out::DebugInfo = findSection(".debug_info");
|
||||
Out::PreinitArray = findSection(".preinit_array");
|
||||
Out::InitArray = findSection(".init_array");
|
||||
Out::FiniArray = findSection(".fini_array");
|
||||
Out::DebugInfo = findSectionInScript(".debug_info");
|
||||
Out::PreinitArray = findSectionInScript(".preinit_array");
|
||||
Out::InitArray = findSectionInScript(".init_array");
|
||||
Out::FiniArray = findSectionInScript(".fini_array");
|
||||
|
||||
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
|
||||
// symbols for sections, so that the runtime can get the start and end
|
||||
// addresses of each section by section name. Add such symbols.
|
||||
if (!Config->Relocatable) {
|
||||
addStartEndSymbols();
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
addStartStopSymbols(Sec);
|
||||
for (BaseCommand *Base : Script->Opt.Commands)
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
|
||||
if (Cmd->Sec)
|
||||
addStartStopSymbols(Cmd->Sec);
|
||||
}
|
||||
|
||||
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
|
||||
@ -1218,9 +1246,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
return;
|
||||
|
||||
addPredefinedSections();
|
||||
removeUnusedSyntheticSections(OutputSections);
|
||||
removeUnusedSyntheticSections();
|
||||
|
||||
clearOutputSections();
|
||||
sortSections();
|
||||
|
||||
// Now that we have the final list, create a list of all the
|
||||
@ -1257,12 +1284,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
|
||||
}
|
||||
|
||||
// Compute the size of .rela.dyn and .rela.plt early since we need
|
||||
// them to populate .dynamic.
|
||||
for (SyntheticSection *SS : {In<ELFT>::RelaDyn, In<ELFT>::RelaPlt})
|
||||
if (SS->getParent() && !SS->empty())
|
||||
SS->getParent()->assignOffsets();
|
||||
|
||||
// Dynamic section must be the last one in this list and dynamic
|
||||
// symbol table section (DynSymTab) must be the first one.
|
||||
applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo,
|
||||
@ -1286,6 +1307,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
// are out of range. This will need to turn into a loop that converges
|
||||
// when no more Thunks are added
|
||||
ThunkCreator TC;
|
||||
Script->assignAddresses();
|
||||
if (TC.createThunks(OutputSectionCommands)) {
|
||||
applySynthetic({InX::MipsGot},
|
||||
[](SyntheticSection *SS) { SS->updateAllocSize(); });
|
||||
@ -1308,21 +1330,18 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
|
||||
// ARM ABI requires .ARM.exidx to be terminated by some piece of data.
|
||||
// We have the terminater synthetic section class. Add that at the end.
|
||||
auto *OS = dyn_cast_or_null<OutputSection>(findSection(".ARM.exidx"));
|
||||
if (!OS || OS->Sections.empty() || Config->Relocatable)
|
||||
OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx");
|
||||
if (!Cmd || Cmd->Commands.empty() || Config->Relocatable)
|
||||
return;
|
||||
|
||||
auto *Sentinel = make<ARMExidxSentinelSection>();
|
||||
OS->addSection(Sentinel);
|
||||
// If there are linker script commands existing at this point then add the
|
||||
// sentinel to the last of these too.
|
||||
if (OutputSectionCommand *C = Script->getCmd(OS)) {
|
||||
auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
|
||||
[](const BaseCommand *Base) {
|
||||
return isa<InputSectionDescription>(Base);
|
||||
});
|
||||
cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
|
||||
}
|
||||
Cmd->Sec->addSection(Sentinel);
|
||||
// Add the sentinel to the last of these too.
|
||||
auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
|
||||
[](const BaseCommand *Base) {
|
||||
return isa<InputSectionDescription>(Base);
|
||||
});
|
||||
cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
|
||||
}
|
||||
|
||||
// The linker is expected to define SECNAME_start and SECNAME_end
|
||||
@ -1346,7 +1365,7 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
|
||||
Define("__init_array_start", "__init_array_end", Out::InitArray);
|
||||
Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
|
||||
|
||||
if (OutputSection *Sec = findSection(".ARM.exidx"))
|
||||
if (OutputSection *Sec = findSectionInScript(".ARM.exidx"))
|
||||
Define("__exidx_start", "__exidx_end", Sec);
|
||||
}
|
||||
|
||||
@ -1366,9 +1385,10 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
|
||||
|
||||
template <class ELFT>
|
||||
OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands)
|
||||
if (Cmd->Name == Name)
|
||||
return Cmd;
|
||||
for (BaseCommand *Base : Script->Opt.Commands)
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
|
||||
if (Cmd->Name == Name)
|
||||
return Cmd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1378,13 +1398,6 @@ template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
if (Sec->Name == Name)
|
||||
return Sec;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool needsPtLoad(OutputSection *Sec) {
|
||||
if (!(Sec->Flags & SHF_ALLOC))
|
||||
return false;
|
||||
@ -1446,7 +1459,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
|
||||
// different flags or is loaded at a discontiguous address using AT linker
|
||||
// script command.
|
||||
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
|
||||
if (Script->hasLMA(Sec) || Flags != NewFlags) {
|
||||
if (Cmd->LMAExpr || Flags != NewFlags) {
|
||||
Load = AddHdr(PT_LOAD, NewFlags);
|
||||
Flags = NewFlags;
|
||||
}
|
||||
@ -1514,7 +1527,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->Type == SHT_NOTE) {
|
||||
if (!Note || Script->hasLMA(Sec))
|
||||
if (!Note || Cmd->LMAExpr)
|
||||
Note = AddHdr(PT_NOTE, PF_R);
|
||||
Note->add(Sec);
|
||||
} else {
|
||||
@ -1528,11 +1541,9 @@ template <class ELFT>
|
||||
void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) {
|
||||
if (Config->EMachine != EM_ARM)
|
||||
return;
|
||||
auto I =
|
||||
std::find_if(OutputSectionCommands.begin(), OutputSectionCommands.end(),
|
||||
[](OutputSectionCommand *Cmd) {
|
||||
return Cmd->Sec->Type == SHT_ARM_EXIDX;
|
||||
});
|
||||
auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) {
|
||||
return Cmd->Sec->Type == SHT_ARM_EXIDX;
|
||||
});
|
||||
if (I == OutputSectionCommands.end())
|
||||
return;
|
||||
|
||||
|
@ -508,9 +508,9 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
|
||||
if (dyldInfo) {
|
||||
// If any exports, extract and add to normalized exportInfo vector.
|
||||
if (dyldInfo->export_size) {
|
||||
const uint8_t *trieStart = reinterpret_cast<const uint8_t*>(start +
|
||||
dyldInfo->export_off);
|
||||
ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size);
|
||||
const uint8_t *trieStart = reinterpret_cast<const uint8_t *>(
|
||||
start + read32(&dyldInfo->export_off, isBig));
|
||||
ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig));
|
||||
for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) {
|
||||
Export normExport;
|
||||
normExport.name = trieExport.name().copy(f->ownedAllocations);
|
||||
|
BIN
test/COFF/Inputs/library-arm64.lib
Normal file
BIN
test/COFF/Inputs/library-arm64.lib
Normal file
Binary file not shown.
BIN
test/COFF/Inputs/pdb-diff-cl.pdb
Normal file
BIN
test/COFF/Inputs/pdb-diff-cl.pdb
Normal file
Binary file not shown.
10
test/COFF/Inputs/pdb-diff.cpp
Normal file
10
test/COFF/Inputs/pdb-diff.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
// Build with cl:
|
||||
// cl.exe /Z7 pdb-diff.cpp /link /debug /pdb:pdb-diff-cl.pdb
|
||||
// /nodefaultlib /entry:main
|
||||
// Build with lld (after running the above cl command):
|
||||
// lld-link.exe /debug /pdb:pdb-diff-lld.pdb /nodefaultlib
|
||||
// /entry:main pdb-diff.obj
|
||||
|
||||
void *__purecall = 0;
|
||||
|
||||
int main() { return 42; }
|
BIN
test/COFF/Inputs/pdb-diff.obj
Normal file
BIN
test/COFF/Inputs/pdb-diff.obj
Normal file
Binary file not shown.
425
test/COFF/Inputs/pdb-scopes-a.yaml
Normal file
425
test/COFF/Inputs/pdb-scopes-a.yaml
Normal file
@ -0,0 +1,425 @@
|
||||
--- !COFF
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: .drectve
|
||||
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
|
||||
Alignment: 1
|
||||
SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
|
||||
- Name: '.debug$S'
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
Subsections:
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_OBJNAME
|
||||
ObjNameSym:
|
||||
Signature: 0
|
||||
ObjectName: 'C:\src\llvm-project\build\a.obj'
|
||||
- Kind: S_COMPILE3
|
||||
Compile3Sym:
|
||||
Flags: [ SecurityChecks, HotPatch ]
|
||||
Machine: X64
|
||||
FrontendMajor: 19
|
||||
FrontendMinor: 0
|
||||
FrontendBuild: 24215
|
||||
FrontendQFE: 1
|
||||
BackendMajor: 19
|
||||
BackendMinor: 0
|
||||
BackendBuild: 24215
|
||||
BackendQFE: 1
|
||||
Version: 'Microsoft (R) Optimizing Compiler'
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_GPROC32_ID
|
||||
ProcSym:
|
||||
CodeSize: 5
|
||||
DbgStart: 4
|
||||
DbgEnd: 4
|
||||
FunctionType: 4099
|
||||
Flags: [ ]
|
||||
DisplayName: g
|
||||
- Kind: S_FRAMEPROC
|
||||
FrameProcSym:
|
||||
TotalFrameBytes: 0
|
||||
PaddingFrameBytes: 0
|
||||
OffsetToPadding: 0
|
||||
BytesOfCalleeSavedRegisters: 0
|
||||
OffsetOfExceptionHandler: 0
|
||||
SectionIdOfExceptionHandler: 0
|
||||
Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 8
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: x
|
||||
- Kind: S_PROC_ID_END
|
||||
ScopeEndSym:
|
||||
- !Lines
|
||||
CodeSize: 5
|
||||
Flags: [ ]
|
||||
RelocOffset: 0
|
||||
RelocSegment: 0
|
||||
Blocks:
|
||||
- FileName: 'c:\src\llvm-project\build\a.c'
|
||||
Lines:
|
||||
- Offset: 0
|
||||
LineStart: 1
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
Columns:
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_GPROC32_ID
|
||||
ProcSym:
|
||||
CodeSize: 58
|
||||
DbgStart: 8
|
||||
DbgEnd: 53
|
||||
FunctionType: 4101
|
||||
Flags: [ ]
|
||||
DisplayName: main
|
||||
- Kind: S_FRAMEPROC
|
||||
FrameProcSym:
|
||||
TotalFrameBytes: 56
|
||||
PaddingFrameBytes: 0
|
||||
OffsetToPadding: 0
|
||||
BytesOfCalleeSavedRegisters: 0
|
||||
OffsetOfExceptionHandler: 0
|
||||
SectionIdOfExceptionHandler: 0
|
||||
Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 64
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: argc
|
||||
- Kind: S_BLOCK32
|
||||
BlockSym:
|
||||
CodeSize: 17
|
||||
Offset: 15
|
||||
BlockName: ''
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 32
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: x
|
||||
- Kind: S_END
|
||||
ScopeEndSym:
|
||||
- Kind: S_BLOCK32
|
||||
BlockSym:
|
||||
CodeSize: 17
|
||||
Offset: 34
|
||||
BlockName: ''
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 36
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: y
|
||||
- Kind: S_END
|
||||
ScopeEndSym:
|
||||
- Kind: S_PROC_ID_END
|
||||
ScopeEndSym:
|
||||
- !Lines
|
||||
CodeSize: 58
|
||||
Flags: [ ]
|
||||
RelocOffset: 0
|
||||
RelocSegment: 0
|
||||
Blocks:
|
||||
- FileName: 'c:\src\llvm-project\build\a.c'
|
||||
Lines:
|
||||
- Offset: 0
|
||||
LineStart: 3
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 8
|
||||
LineStart: 4
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 15
|
||||
LineStart: 5
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 23
|
||||
LineStart: 6
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 32
|
||||
LineStart: 7
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 34
|
||||
LineStart: 8
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 42
|
||||
LineStart: 9
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 51
|
||||
LineStart: 11
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
Columns:
|
||||
- !FileChecksums
|
||||
Checksums:
|
||||
- FileName: 'c:\src\llvm-project\build\a.c'
|
||||
Kind: MD5
|
||||
Checksum: 7FA72225C3F5630316383BD8BCC3EF72
|
||||
- !StringTable
|
||||
Strings:
|
||||
- 'c:\src\llvm-project\build\a.c'
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_BUILDINFO
|
||||
BuildInfoSym:
|
||||
BuildId: 4110
|
||||
Relocations:
|
||||
- VirtualAddress: 152
|
||||
SymbolName: g
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 156
|
||||
SymbolName: g
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 220
|
||||
SymbolName: g
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 224
|
||||
SymbolName: g
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 292
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 296
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 369
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 373
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 412
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 416
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 452
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 456
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- Name: '.debug$T'
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
Types:
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 116 ]
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 3
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 1
|
||||
ArgumentList: 4096
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4097
|
||||
Attrs: 65548
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4097
|
||||
Name: g
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 116
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 1
|
||||
ArgumentList: 4096
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4100
|
||||
Name: main
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4097
|
||||
Name: f
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'C:\src\llvm-project\build'
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
|
||||
- Kind: LF_SUBSTR_LIST
|
||||
StringList:
|
||||
StringIndices: [ 4105 ]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 4106
|
||||
String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: a.c
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'C:\src\llvm-project\build\vc140.pdb'
|
||||
- Kind: LF_BUILDINFO
|
||||
BuildInfo:
|
||||
ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ]
|
||||
- Name: '.text$mn'
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 16
|
||||
SectionData: 894C2408C3CCCCCCCCCCCCCCCCCCCCCC894C24084883EC38837C2440007413C74424202A0000008B4C2420E800000000EB11C74424240D0000008B4C2424E80000000033C04883C438C3
|
||||
Relocations:
|
||||
- VirtualAddress: 44
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_REL32
|
||||
- VirtualAddress: 63
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_REL32
|
||||
- Name: .xdata
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: '0108010008620000'
|
||||
- Name: .pdata
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: 000000003A00000000000000
|
||||
Relocations:
|
||||
- VirtualAddress: 0
|
||||
SymbolName: '$LN5'
|
||||
Type: IMAGE_REL_AMD64_ADDR32NB
|
||||
- VirtualAddress: 4
|
||||
SymbolName: '$LN5'
|
||||
Type: IMAGE_REL_AMD64_ADDR32NB
|
||||
- VirtualAddress: 8
|
||||
SymbolName: '$unwind$main'
|
||||
Type: IMAGE_REL_AMD64_ADDR32NB
|
||||
symbols:
|
||||
- Name: .drectve
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 47
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.debug$S'
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 628
|
||||
NumberOfRelocations: 12
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.debug$T'
|
||||
Value: 0
|
||||
SectionNumber: 3
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 624
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.text$mn'
|
||||
Value: 0
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 74
|
||||
NumberOfRelocations: 2
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 2120072435
|
||||
Number: 0
|
||||
- Name: g
|
||||
Value: 0
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: f
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: main
|
||||
Value: 16
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: '$LN5'
|
||||
Value: 16
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_LABEL
|
||||
- Name: .xdata
|
||||
Value: 0
|
||||
SectionNumber: 5
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 8
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 3137252093
|
||||
Number: 0
|
||||
- Name: '$unwind$main'
|
||||
Value: 0
|
||||
SectionNumber: 5
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: .pdata
|
||||
Value: 0
|
||||
SectionNumber: 6
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 12
|
||||
NumberOfRelocations: 3
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 336416693
|
||||
Number: 0
|
||||
- Name: '$pdata$main'
|
||||
Value: 0
|
||||
SectionNumber: 6
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
...
|
365
test/COFF/Inputs/pdb-scopes-b.yaml
Normal file
365
test/COFF/Inputs/pdb-scopes-b.yaml
Normal file
@ -0,0 +1,365 @@
|
||||
--- !COFF
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: .drectve
|
||||
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
|
||||
Alignment: 1
|
||||
SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220
|
||||
- Name: '.debug$S'
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
Subsections:
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_OBJNAME
|
||||
ObjNameSym:
|
||||
Signature: 0
|
||||
ObjectName: 'C:\src\llvm-project\build\b.obj'
|
||||
- Kind: S_COMPILE3
|
||||
Compile3Sym:
|
||||
Flags: [ SecurityChecks, HotPatch ]
|
||||
Machine: X64
|
||||
FrontendMajor: 19
|
||||
FrontendMinor: 0
|
||||
FrontendBuild: 24215
|
||||
FrontendQFE: 1
|
||||
BackendMajor: 19
|
||||
BackendMinor: 0
|
||||
BackendBuild: 24215
|
||||
BackendQFE: 1
|
||||
Version: 'Microsoft (R) Optimizing Compiler'
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_GPROC32_ID
|
||||
ProcSym:
|
||||
CodeSize: 62
|
||||
DbgStart: 8
|
||||
DbgEnd: 57
|
||||
FunctionType: 4101
|
||||
Flags: [ ]
|
||||
DisplayName: f
|
||||
- Kind: S_FRAMEPROC
|
||||
FrameProcSym:
|
||||
TotalFrameBytes: 56
|
||||
PaddingFrameBytes: 0
|
||||
OffsetToPadding: 0
|
||||
BytesOfCalleeSavedRegisters: 0
|
||||
OffsetOfExceptionHandler: 0
|
||||
SectionIdOfExceptionHandler: 0
|
||||
Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 64
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: x
|
||||
- Kind: S_BLOCK32
|
||||
BlockSym:
|
||||
CodeSize: 20
|
||||
Offset: 15
|
||||
BlockName: ''
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 32
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: y
|
||||
- Kind: S_END
|
||||
ScopeEndSym:
|
||||
- Kind: S_BLOCK32
|
||||
BlockSym:
|
||||
CodeSize: 20
|
||||
Offset: 37
|
||||
BlockName: ''
|
||||
- Kind: S_REGREL32
|
||||
RegRelativeSym:
|
||||
Offset: 36
|
||||
Type: 116
|
||||
Register: RSP
|
||||
VarName: w
|
||||
- Kind: S_END
|
||||
ScopeEndSym:
|
||||
- Kind: S_PROC_ID_END
|
||||
ScopeEndSym:
|
||||
- !Lines
|
||||
CodeSize: 62
|
||||
Flags: [ ]
|
||||
RelocOffset: 0
|
||||
RelocSegment: 0
|
||||
Blocks:
|
||||
- FileName: 'c:\src\llvm-project\build\b.c'
|
||||
Lines:
|
||||
- Offset: 0
|
||||
LineStart: 2
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 8
|
||||
LineStart: 3
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 15
|
||||
LineStart: 4
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 26
|
||||
LineStart: 5
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 35
|
||||
LineStart: 6
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 37
|
||||
LineStart: 7
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 48
|
||||
LineStart: 8
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
- Offset: 57
|
||||
LineStart: 10
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
Columns:
|
||||
- !FileChecksums
|
||||
Checksums:
|
||||
- FileName: 'c:\src\llvm-project\build\b.c'
|
||||
Kind: MD5
|
||||
Checksum: 8E8C92DB46478902EBEAEBFCFF15A6E0
|
||||
- !StringTable
|
||||
Strings:
|
||||
- 'c:\src\llvm-project\build\b.c'
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_BUILDINFO
|
||||
BuildInfoSym:
|
||||
BuildId: 4110
|
||||
Relocations:
|
||||
- VirtualAddress: 152
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 156
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 223
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 227
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 266
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 270
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 308
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 312
|
||||
SymbolName: f
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- Name: '.debug$T'
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
Types:
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 0 ]
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 3
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 0
|
||||
ArgumentList: 4096
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4097
|
||||
Attrs: 65548
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 116 ]
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 3
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 1
|
||||
ArgumentList: 4099
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4100
|
||||
Name: f
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4097
|
||||
Name: g
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'C:\src\llvm-project\build'
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe'
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um'
|
||||
- Kind: LF_SUBSTR_LIST
|
||||
StringList:
|
||||
StringIndices: [ 4105 ]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 4106
|
||||
String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X'
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: b.c
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'C:\src\llvm-project\build\vc140.pdb'
|
||||
- Kind: LF_BUILDINFO
|
||||
BuildInfo:
|
||||
ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ]
|
||||
- Name: '.text$mn'
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 16
|
||||
SectionData: 894C24084883EC38837C24400074168B44244083C003894424208B4C2420E800000000EB148B44244083C004894424248B4C2424E8000000004883C438C3
|
||||
Relocations:
|
||||
- VirtualAddress: 31
|
||||
SymbolName: g
|
||||
Type: IMAGE_REL_AMD64_REL32
|
||||
- VirtualAddress: 53
|
||||
SymbolName: g
|
||||
Type: IMAGE_REL_AMD64_REL32
|
||||
- Name: .xdata
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: '0108010008620000'
|
||||
- Name: .pdata
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: '000000003E00000000000000'
|
||||
Relocations:
|
||||
- VirtualAddress: 0
|
||||
SymbolName: '$LN5'
|
||||
Type: IMAGE_REL_AMD64_ADDR32NB
|
||||
- VirtualAddress: 4
|
||||
SymbolName: '$LN5'
|
||||
Type: IMAGE_REL_AMD64_ADDR32NB
|
||||
- VirtualAddress: 8
|
||||
SymbolName: '$unwind$f'
|
||||
Type: IMAGE_REL_AMD64_ADDR32NB
|
||||
symbols:
|
||||
- Name: .drectve
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 47
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.debug$S'
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 484
|
||||
NumberOfRelocations: 8
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.debug$T'
|
||||
Value: 0
|
||||
SectionNumber: 3
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 616
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.text$mn'
|
||||
Value: 0
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 62
|
||||
NumberOfRelocations: 2
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 3841032836
|
||||
Number: 0
|
||||
- Name: g
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: f
|
||||
Value: 0
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: '$LN5'
|
||||
Value: 0
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_LABEL
|
||||
- Name: .xdata
|
||||
Value: 0
|
||||
SectionNumber: 5
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 8
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 3137252093
|
||||
Number: 0
|
||||
- Name: '$unwind$f'
|
||||
Value: 0
|
||||
SectionNumber: 5
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: .pdata
|
||||
Value: 0
|
||||
SectionNumber: 6
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 12
|
||||
NumberOfRelocations: 3
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 2420588879
|
||||
Number: 0
|
||||
- Name: '$pdata$f'
|
||||
Value: 0
|
||||
SectionNumber: 6
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
...
|
46
test/COFF/arm64-magic.yaml
Normal file
46
test/COFF/arm64-magic.yaml
Normal file
@ -0,0 +1,46 @@
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj
|
||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
|
||||
|
||||
# CHECK: Format: COFF-ARM64
|
||||
# CHECK: Arch: aarch64
|
||||
# CHECK: AddressSize: 64bit
|
||||
# CHECK: ImageFileHeader {
|
||||
# CHECK: Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64)
|
||||
# CHECK: Characteristics [ (0x22)
|
||||
# CHECK: IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
|
||||
# CHECK: IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20)
|
||||
# CHECK: ]
|
||||
# CHECK: }
|
||||
# CHECK: ImageOptionalHeader {
|
||||
# CHECK: Magic: 0x20B
|
||||
|
||||
--- !COFF
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_ARM64
|
||||
Characteristics: []
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: 'e0031f2ac0035fd6'
|
||||
symbols:
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 8
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 1
|
||||
- Name: mainCRTStartup
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
136
test/COFF/arm64-relocs-imports.test
Normal file
136
test/COFF/arm64-relocs-imports.test
Normal file
@ -0,0 +1,136 @@
|
||||
# REQUIRES: aarch64
|
||||
|
||||
# RUN: yaml2obj < %s > %t.obj
|
||||
# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
|
||||
# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib
|
||||
# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
|
||||
|
||||
# BEFORE: Disassembly of section .text:
|
||||
# BEFORE: 0: fe 0f 1f f8 str x30, [sp, #-16]!
|
||||
# BEFORE: 4: 00 00 00 90 adrp x0, #0
|
||||
# BEFORE: 8: 00 08 00 91 add x0, x0, #2
|
||||
# BEFORE: c: 00 00 00 94 bl #0
|
||||
# BEFORE: 10: 00 01 40 39 ldrb w0, [x8]
|
||||
# BEFORE: 14: 00 01 40 79 ldrh w0, [x8]
|
||||
# BEFORE: 18: 00 01 40 b9 ldr w0, [x8]
|
||||
# BEFORE: 1c: 00 01 40 f9 ldr x0, [x8]
|
||||
# BEFORE: 20: e0 03 1f 2a mov w0, wzr
|
||||
# BEFORE: 24: fe 07 41 f8 ldr x30, [sp], #16
|
||||
# BEFORE: 28: c0 03 5f d6 ret
|
||||
# BEFORE: 2c: 08 00 00 00 <unknown>
|
||||
# BEFORE: 30: 00 00 00 00 <unknown>
|
||||
|
||||
# AFTER: Disassembly of section .text:
|
||||
# AFTER: 140002000: fe 0f 1f f8 str x30, [sp, #-16]!
|
||||
# AFTER: 140002004: e0 ff ff f0 adrp x0, #-4096
|
||||
# AFTER: 140002008: 00 18 00 91 add x0, x0, #6
|
||||
# AFTER: 14000200c: 0a 00 00 94 bl #40
|
||||
# AFTER: 140002010: 00 21 40 39 ldrb w0, [x8, #8]
|
||||
# AFTER: 140002014: 00 11 40 79 ldrh w0, [x8, #8]
|
||||
# AFTER: 140002018: 00 09 40 b9 ldr w0, [x8, #8]
|
||||
# AFTER: 14000201c: 00 05 40 f9 ldr x0, [x8, #8]
|
||||
# AFTER: 140002020: e0 03 1f 2a mov w0, wzr
|
||||
# AFTER: 140002024: fe 07 41 f8 ldr x30, [sp], #16
|
||||
# AFTER: 140002028: c0 03 5f d6 ret
|
||||
# AFTER: 14000202c: 10 10 00 40 <unknown>
|
||||
# AFTER: 140002030: 01 00 00 00 <unknown>
|
||||
# AFTER: 140002034: 10 00 00 b0 adrp x16, #4096
|
||||
# AFTER: 140002038: 10 1e 40 f9 ldr x16, [x16, #56]
|
||||
# AFTER: 14000203c: 00 02 1f d6 br x16
|
||||
|
||||
--- !COFF
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_ARM64
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F9E0031F2AFE0741F8C0035FD60800000000000000
|
||||
Relocations:
|
||||
- VirtualAddress: 4
|
||||
SymbolName: .Lstr
|
||||
Type: 4
|
||||
- VirtualAddress: 8
|
||||
SymbolName: .Lstr
|
||||
Type: 6
|
||||
- VirtualAddress: 12
|
||||
SymbolName: function
|
||||
Type: 3
|
||||
- VirtualAddress: 16
|
||||
SymbolName: .Lglobal
|
||||
Type: 7
|
||||
- VirtualAddress: 20
|
||||
SymbolName: .Lglobal
|
||||
Type: 7
|
||||
- VirtualAddress: 24
|
||||
SymbolName: .Lglobal
|
||||
Type: 7
|
||||
- VirtualAddress: 28
|
||||
SymbolName: .Lglobal
|
||||
Type: 7
|
||||
- VirtualAddress: 44
|
||||
SymbolName: .Lglobal
|
||||
Type: 14
|
||||
- Name: .data
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
|
||||
Alignment: 4
|
||||
SectionData: ''
|
||||
- Name: .bss
|
||||
Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
|
||||
Alignment: 4
|
||||
SectionData: ''
|
||||
- Name: .rdata
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
SectionData: 00000000202068656C6C6F20776F726C6400
|
||||
symbols:
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 28
|
||||
NumberOfRelocations: 3
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 1438860354
|
||||
Number: 1
|
||||
- Name: .rdata
|
||||
Value: 0
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 12
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 872944732
|
||||
Number: 4
|
||||
- Name: main
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: .Lstr
|
||||
Value: 4
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: .Lglobal
|
||||
Value: 8
|
||||
SectionNumber: 4
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
- Name: function
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
@ -8,10 +8,206 @@
|
||||
# RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \
|
||||
# RUN: %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res
|
||||
|
||||
# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s
|
||||
|
||||
# RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \
|
||||
# RUN: FileCheck %s
|
||||
|
||||
CHECK: ResourceTableRVA: 0x1000
|
||||
CHECK-NEXT: ResourceTableSize: 0xC1C
|
||||
CHECK-DAG: Resources [
|
||||
CHECK-NEXT: Total Number of Resources: 13
|
||||
CHECK-DAG: .rsrc Data (
|
||||
CHECK-NEXT: 0000: 00000000 00000000 00000000 01000600 |................|
|
||||
CHECK-NEXT: 0010: 38030080 48000080 02000000 60000080 |8...H.......`...|
|
||||
CHECK-NEXT: 0020: 04000000 80000080 05000000 A0000080 |................|
|
||||
CHECK-NEXT: 0030: 06000000 B8000080 09000000 D0000080 |................|
|
||||
CHECK-NEXT: 0040: 0A000000 F0000080 00000000 00000000 |................|
|
||||
CHECK-NEXT: 0050: 00000000 01000000 50030080 08010080 |........P.......|
|
||||
CHECK-NEXT: 0060: 00000000 00000000 00000000 02000000 |................|
|
||||
CHECK-NEXT: 0070: FE020080 20010080 0C030080 38010080 |.... .......8...|
|
||||
CHECK-NEXT: 0080: 00000000 00000000 00000000 01000100 |................|
|
||||
CHECK-NEXT: 0090: 2C030080 50010080 60380000 68010080 |,...P...`8..h...|
|
||||
CHECK-NEXT: 00A0: 00000000 00000000 00000000 01000000 |................|
|
||||
CHECK-NEXT: 00B0: 16030080 80010080 00000000 00000000 |................|
|
||||
CHECK-NEXT: 00C0: 00000000 00000100 01000000 98010080 |................|
|
||||
CHECK-NEXT: 00D0: 00000000 00000000 00000000 01000100 |................|
|
||||
CHECK-NEXT: 00E0: E0020080 B0010080 0C000000 D0010080 |................|
|
||||
CHECK-NEXT: 00F0: 00000000 00000000 00000000 01000000 |................|
|
||||
CHECK-NEXT: 0100: 66030080 E8010080 00000000 00000000 |f...............|
|
||||
CHECK-NEXT: 0110: 00000000 00000100 09040000 10020000 |................|
|
||||
CHECK-NEXT: 0120: 00000000 00000000 00000000 00000100 |................|
|
||||
CHECK-NEXT: 0130: 09040000 20020000 00000000 00000000 |.... ...........|
|
||||
CHECK-NEXT: 0140: 00000000 00000100 09040000 30020000 |............0...|
|
||||
CHECK-NEXT: 0150: 00000000 00000000 00000000 00000100 |................|
|
||||
CHECK-NEXT: 0160: 090C0000 40020000 00000000 00000000 |....@...........|
|
||||
CHECK-NEXT: 0170: 00000000 00000100 04080000 50020000 |............P...|
|
||||
CHECK-NEXT: 0180: 00000000 00000000 00000000 00000100 |................|
|
||||
CHECK-NEXT: 0190: 09040000 60020000 00000000 00000000 |....`...........|
|
||||
CHECK-NEXT: 01A0: 00000000 00000100 09040000 70020000 |............p...|
|
||||
CHECK-NEXT: 01B0: 00000000 00000000 00000000 00000200 |................|
|
||||
CHECK-NEXT: 01C0: 09040000 80020000 04080000 90020000 |................|
|
||||
CHECK-NEXT: 01D0: 00000000 00000000 00000000 00000100 |................|
|
||||
CHECK-NEXT: 01E0: 09040000 A0020000 00000000 00000000 |................|
|
||||
CHECK-NEXT: 01F0: 00000000 00000300 09040000 B0020000 |................|
|
||||
CHECK-NEXT: 0200: 04080000 C0020000 07100000 D0020000 |................|
|
||||
CHECK-NEXT: 0210: FC1A0000 39000000 00000000 00000000 |....9...........|
|
||||
CHECK-NEXT: 0220: C4130000 28030000 00000000 00000000 |....(...........|
|
||||
CHECK-NEXT: 0230: EC160000 28030000 00000000 00000000 |....(...........|
|
||||
CHECK-NEXT: 0240: CC1A0000 30000000 00000000 00000000 |....0...........|
|
||||
CHECK-NEXT: 0250: 141A0000 2E000000 00000000 00000000 |................|
|
||||
CHECK-NEXT: 0260: 441A0000 6C000000 00000000 00000000 |D...l...........|
|
||||
CHECK-NEXT: 0270: 7C130000 2A000000 00000000 00000000 ||...*...........|
|
||||
CHECK-NEXT: 0280: AC130000 18000000 00000000 00000000 |................|
|
||||
CHECK-NEXT: 0290: 041C0000 18000000 00000000 00000000 |................|
|
||||
CHECK-NEXT: 02A0: B41A0000 18000000 00000000 00000000 |................|
|
||||
CHECK-NEXT: 02B0: 3C1B0000 36000000 00000000 00000000 |<...6...........|
|
||||
CHECK-NEXT: 02C0: 741B0000 43000000 00000000 00000000 |t...C...........|
|
||||
CHECK-NEXT: 02D0: BC1B0000 42000000 00000000 00000000 |....B...........|
|
||||
CHECK-NEXT: 02E0: 0E004D00 59004100 43004300 45004C00 |..M.Y.A.C.C.E.L.|
|
||||
CHECK-NEXT: 02F0: 45005200 41005400 4F005200 53000600 |E.R.A.T.O.R.S...|
|
||||
CHECK-NEXT: 0300: 43005500 52005300 4F005200 04004F00 |C.U.R.S.O.R...O.|
|
||||
CHECK-NEXT: 0310: 4B004100 59000A00 54004500 53005400 |K.A.Y...T.E.S.T.|
|
||||
CHECK-NEXT: 0320: 44004900 41004C00 4F004700 05002200 |D.I.A.L.O.G...".|
|
||||
CHECK-NEXT: 0330: 45004100 54002200 0B005300 54005200 |E.A.T."...S.T.R.|
|
||||
CHECK-NEXT: 0340: 49004E00 47004100 52005200 41005900 |I.N.G.A.R.R.A.Y.|
|
||||
CHECK-NEXT: 0350: 0A004D00 59005200 45005300 4F005500 |..M.Y.R.E.S.O.U.|
|
||||
CHECK-NEXT: 0360: 52004300 45000900 52004100 4E004400 |R.C.E...R.A.N.D.|
|
||||
CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000500 |O.M.D.A.T.......|
|
||||
CHECK-NEXT: 0380: 48006500 6C006C00 6F000000 00000000 |H.e.l.l.o.......|
|
||||
CHECK-NEXT: 0390: 00000000 00000000 00000000 00000000 |................|
|
||||
CHECK-NEXT: 03A0: 00000000 00000000 00000000 11000300 |................|
|
||||
CHECK-NEXT: 03B0: E7030000 0D004400 4C040000 82001200 |......D.L.......|
|
||||
CHECK-NEXT: 03C0: BC010000 28000000 10000000 10000000 |....(...........|
|
||||
CHECK-NEXT: 03D0: 01001800 00000000 00030000 C40E0000 |................|
|
||||
CHECK-NEXT: 03E0: C40E0000 00000000 00000000 FFFFFFFF |................|
|
||||
CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0430: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0440: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0460: FF7F7F7F 7C7C7C78 78787575 75FFFFFF |....|||xxxuuu...|
|
||||
CHECK-NEXT: 0470: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF 979797FF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0490: FF838383 AAAAAADB DBDB7979 79757575 |..........yyyuuu|
|
||||
CHECK-NEXT: 04A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF 9C9C9C98 9898FFFF |................|
|
||||
CHECK-NEXT: 04C0: FF888888 DBDBDBB7 B7B77D7D 7DFFFFFF |..........}}}...|
|
||||
CHECK-NEXT: 04D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF A0A0A09C 9C9C9393 |................|
|
||||
CHECK-NEXT: 04F0: 93ADADAD F2F2F284 84848181 81FFFFFF |................|
|
||||
CHECK-NEXT: 0500: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF A4A4A4D7 D7D79D9D |................|
|
||||
CHECK-NEXT: 0520: 9DD0D0D0 EEEEEE91 91918D8D 8DFFFFFF |................|
|
||||
CHECK-NEXT: 0530: FFFFFF81 81817E7E 7EFFFFFF FFFFFFFF |......~~~.......|
|
||||
CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF A9A9A9F2 F2F2E5E5 |................|
|
||||
CHECK-NEXT: 0550: E5E2E2E2 95959591 91918D8D 8D898989 |................|
|
||||
CHECK-NEXT: 0560: 868686FF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF ADADADF2 F2F2E1E1 |................|
|
||||
CHECK-NEXT: 0580: E1DFDFDF E7E7E7E4 E4E4BBBB BB8E8E8E |................|
|
||||
CHECK-NEXT: 0590: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF B5B5B5F2 F2F2E8E8 |................|
|
||||
CHECK-NEXT: 05B0: E8E7E7E7 EAEAEAC6 C6C69E9E 9EFFFFFF |................|
|
||||
CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF B9B9B9F4 F4F4ECEC |................|
|
||||
CHECK-NEXT: 05E0: ECEDEDED CBCBCBA7 A7A7FFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF |................|
|
||||
CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5 |................|
|
||||
CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF C4C4C4D9 D9D9BEBE |................|
|
||||
CHECK-NEXT: 0670: BEFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF |................|
|
||||
CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 06D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF 28000000 |............(...|
|
||||
CHECK-NEXT: 06F0: 10000000 10000000 01001800 00000000 |................|
|
||||
CHECK-NEXT: 0700: 00030000 C40E0000 C40E0000 00000000 |................|
|
||||
CHECK-NEXT: 0710: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0750: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0760: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0770: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0780: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0790: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 07A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 07B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 07C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 07D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 07E0: A0E3A901 B31801B3 1801B318 01B31801 |................|
|
||||
CHECK-NEXT: 07F0: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........|
|
||||
CHECK-NEXT: 0800: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0810: 01B31800 D7331CDB 49DBF9E2 9BEFAF00 |.....3..I.......|
|
||||
CHECK-NEXT: 0820: D73300D7 3301B318 FFFFFFFF FFFFFFFF |.3..3...........|
|
||||
CHECK-NEXT: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86 |.....U..........|
|
||||
CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF FFFFFFFF |....U...........|
|
||||
CHECK-NEXT: 0860: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0870: 01B31800 E676DBFB EC00E676 57EFA5FB |.....v.....vW...|
|
||||
CHECK-NEXT: 0880: FFFD55EE A401B318 FFFFFFFF FFFFFFFF |..U.............|
|
||||
CHECK-NEXT: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887 |................|
|
||||
CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00 |................|
|
||||
CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00 |................|
|
||||
CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0920: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0930: 9FE2A801 B31801B3 1801B318 01B31801 |................|
|
||||
CHECK-NEXT: 0940: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........|
|
||||
CHECK-NEXT: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0980: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0990: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 09A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 09B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 09C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 09D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 09E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 09F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0A00: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
CHECK-NEXT: 0A10: FFFFFFFF 00000000 00006400 79007500 |..........d.y.u.|
|
||||
CHECK-NEXT: 0A20: 00000000 65007300 68006100 6C006100 |....e.s.h.a.l.a.|
|
||||
CHECK-NEXT: 0A30: 00008000 66006B00 61006F00 79006100 |....f.k.a.o.y.a.|
|
||||
CHECK-NEXT: 0A40: 00000000 0000C080 00000000 02000A00 |................|
|
||||
CHECK-NEXT: 0A50: 0A00C800 2C010000 00005400 65007300 |....,.....T.e.s.|
|
||||
CHECK-NEXT: 0A60: 74000000 01000250 00000000 0A000A00 |t......P........|
|
||||
CHECK-NEXT: 0A70: E6000E00 0100FFFF 82004300 6F006E00 |..........C.o.n.|
|
||||
CHECK-NEXT: 0A80: 74006900 6E007500 65003A00 00000000 |t.i.n.u.e.:.....|
|
||||
CHECK-NEXT: 0A90: 00000150 00000000 42008600 A1000D00 |...P....B.......|
|
||||
CHECK-NEXT: 0AA0: 0200FFFF 80002600 4F004B00 00000000 |......&.O.K.....|
|
||||
CHECK-NEXT: 0AB0: 00000000 11005800 A4000000 0D004800 |......X.......H.|
|
||||
CHECK-NEXT: 0AC0: 2E160000 82001200 BC010000 00000000 |................|
|
||||
CHECK-NEXT: 0AD0: 00006400 66006900 73006800 00000000 |..d.f.i.s.h.....|
|
||||
CHECK-NEXT: 0AE0: 65007300 61006C00 61006400 00008000 |e.s.a.l.a.d.....|
|
||||
CHECK-NEXT: 0AF0: 66006400 75006300 6B000000 74686973 |f.d.u.c.k...this|
|
||||
CHECK-NEXT: 0B00: 20697320 61207573 65722064 6566696E | is a user defin|
|
||||
CHECK-NEXT: 0B10: 65642072 65736F75 72636500 69742063 |ed resource.it c|
|
||||
CHECK-NEXT: 0B20: 6F6E7461 696E7320 6D616E79 20737472 |ontains many str|
|
||||
CHECK-NEXT: 0B30: 696E6773 00000000 00000000 74686973 |ings........this|
|
||||
CHECK-NEXT: 0B40: 20697320 61207261 6E646F6D 20626974 | is a random bit|
|
||||
CHECK-NEXT: 0B50: 206F6620 64617461 20746861 74206D65 | of data that me|
|
||||
CHECK-NEXT: 0B60: 616E7320 6E6F7468 696E6700 A9230E14 |ans nothing..#..|
|
||||
CHECK-NEXT: 0B70: F4F60000 7A686534 20736869 34207969 |....zhe4 shi4 yi|
|
||||
CHECK-NEXT: 0B80: 31676534 20737569 326A6931 20646520 |1ge4 sui2ji1 de |
|
||||
CHECK-NEXT: 0B90: 73687534 6A75342C 207A6865 34207969 |shu4ju4, zhe4 yi|
|
||||
CHECK-NEXT: 0BA0: 34776569 347A6865 20736865 6E326D65 |4wei4zhe shen2me|
|
||||
CHECK-NEXT: 0BB0: 00A9230E 14F4F600 00000000 44696573 |..#.........Dies|
|
||||
CHECK-NEXT: 0BC0: 20697374 2065696E 207A7566 C3A46C6C | ist ein zuf..ll|
|
||||
CHECK-NEXT: 0BD0: 69676573 20426974 20766F6E 20446174 |iges Bit von Dat|
|
||||
CHECK-NEXT: 0BE0: 656E2C20 64696520 6E696368 74732062 |en, die nichts b|
|
||||
CHECK-NEXT: 0BF0: 65646575 74657400 A9230E14 F4F60000 |edeutet..#......|
|
||||
CHECK-NEXT: 0C00: 00000000 11000300 E7030000 0D004400 |..............D.|
|
||||
CHECK-NEXT: 0C10: 4C040000 82001200 BC010000 |L...........|
|
||||
CHECK-NEXT: )
|
||||
|
@ -47,7 +47,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler,
|
||||
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
|
||||
CHECK: flags = security checks | hot patchable
|
||||
CHECK: 120 | S_GPROC32_ID [size = 44] `main`
|
||||
CHECK: parent = 0, end = 0, addr = 0002:0000, code size = 24
|
||||
CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 24
|
||||
CHECK: debug start = 4, debug end = 19, flags = none
|
||||
CHECK: 164 | S_FRAMEPROC [size = 32]
|
||||
CHECK: size = 40, padding size = 0, offset to padding = 0
|
||||
@ -58,7 +58,7 @@ CHECK: 200 | S_GDATA32 [size = 24] `global`
|
||||
CHECK: type = 0x0074 (int), addr = 0000:0000
|
||||
CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `4106`
|
||||
CHECK: 232 | S_GPROC32_ID [size = 44] `foo`
|
||||
CHECK: parent = 0, end = 0, addr = 0002:0032, code size = 15
|
||||
CHECK: parent = 0, end = 308, addr = 0002:0032, code size = 15
|
||||
CHECK: debug start = 0, debug end = 14, flags = none
|
||||
CHECK: 276 | S_FRAMEPROC [size = 32]
|
||||
CHECK: size = 0, padding size = 0, offset to padding = 0
|
||||
@ -72,7 +72,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, l
|
||||
CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
|
||||
CHECK: flags = security checks | hot patchable
|
||||
CHECK: 120 | S_GPROC32_ID [size = 44] `bar`
|
||||
CHECK: parent = 0, end = 0, addr = 0002:0048, code size = 14
|
||||
CHECK: parent = 0, end = 196, addr = 0002:0048, code size = 14
|
||||
CHECK: debug start = 4, debug end = 9, flags = none
|
||||
CHECK: 164 | S_FRAMEPROC [size = 32]
|
||||
CHECK: size = 40, padding size = 0, offset to padding = 0
|
||||
|
212
test/COFF/pdb-diff.test
Normal file
212
test/COFF/pdb-diff.test
Normal file
@ -0,0 +1,212 @@
|
||||
This test verifies that we produce PDBs compatible with MSVC in various ways.
|
||||
We check in a cl-generated object file, PDB, and original source which serve
|
||||
as the "baseline" for us to measure against. Then we link the same object
|
||||
file with LLD and compare the two PDBs. Since the baseline object file and
|
||||
PDB are already checked in, we just run LLD on the object file.
|
||||
|
||||
RUN: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj
|
||||
RUN: llvm-pdbutil diff -result -values=false -left-bin-root=%S -right-bin-root=D:/src/llvm-mono/lld/test/COFF/ %T/pdb-diff-lld.pdb %S/Inputs/pdb-diff-cl.pdb | FileCheck %s
|
||||
|
||||
CHECK: ----------------------
|
||||
CHECK-NEXT: | MSF Super Block |
|
||||
CHECK-NEXT: |----------------+---|
|
||||
CHECK-NEXT: | File | |
|
||||
CHECK-NEXT: |----------------+---|
|
||||
CHECK-NEXT: | Block Size | I |
|
||||
CHECK-NEXT: |----------------+---|
|
||||
CHECK-NEXT: | Block Count |
|
||||
CHECK-NEXT: |----------------+---|
|
||||
CHECK-NEXT: | Unknown 1 | I |
|
||||
CHECK-NEXT: |----------------+---|
|
||||
CHECK-NEXT: | Directory Size |
|
||||
CHECK-NEXT: |----------------+---|
|
||||
CHECK-NEXT: ------------------------------------
|
||||
CHECK-NEXT: | Stream Directory |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | File | |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Stream Count | D |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Old MSF Directory | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | PDB Stream | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | TPI Stream | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | DBI Stream | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | IPI Stream | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | New FPO Data | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Section Header Data | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Named Stream "/names" | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Named Stream "/LinkInfo" | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Module "* Linker *" | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | TPI Hash | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | IPI Hash | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Public Symbol Hash | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Public Symbol Records | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Global Symbol Hash | D |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: ------------------------------------
|
||||
CHECK-NEXT: | String Table |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | File | |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Number of Strings | D |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Hash Version | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Byte Size |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Signature | I |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | Empty Strings |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | {{.*}}pdb-diff.cpp | {{[EI]}} |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | $T0 $ebp = $...p $T0 8 + = | D |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: | d:\src\llvm-...er internal) | D |
|
||||
CHECK-NEXT: |------------------------------+---|
|
||||
CHECK-NEXT: ----------------------------
|
||||
CHECK-NEXT: | PDB Stream |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | File | |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Stream Size |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Age | I |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Guid | D |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Signature | D |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Version | I |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Features (set) | I |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Feature | I |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Named Stream Size |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | Named Streams (map) | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | /names | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: | /LinkInfo | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------+---|
|
||||
CHECK-NEXT: ----------------------------------------------
|
||||
CHECK-NEXT: | DBI Stream |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | File | |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Dbi Version | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Age | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Machine | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Flags | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Build Major | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Build Minor | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Build Number | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | PDB DLL Version | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | PDB DLL RBLD | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (FPO) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (Exception) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (Fixup) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (OmapToSrc) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (OmapFromSrc) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (SectionHdr) | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (TokenRidMap) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (Xdata) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (Pdata) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (NewFPO) | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | DBG (SectionHdrOrig) | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Globals Stream | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Publics Stream | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Symbol Records | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Has CTypes | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Is Incrementally Linked | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Is Stripped | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Module Count | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Source File Count | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Module "Inputs\pdb-diff.obj" |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Modi | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Obj File Name | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Debug Stream | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - C11 Byte Size | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - C13 Byte Size | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - # of files | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Pdb File Path Index | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Source File Name Index | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Symbol Byte Size | D |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | Module "* Linker *" |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Modi | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Obj File Name | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Debug Stream | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - C11 Byte Size | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - C13 Byte Size | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - # of files | I |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Pdb File Path Index | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Source File Name Index | {{[EI]}} |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
CHECK-NEXT: | - Symbol Byte Size |
|
||||
CHECK-NEXT: |----------------------------------------+---|
|
||||
|
||||
|
146
test/COFF/pdb-invalid-func-type.yaml
Normal file
146
test/COFF/pdb-invalid-func-type.yaml
Normal file
@ -0,0 +1,146 @@
|
||||
# This test has an S_GPROC32_ID symbol with an invalid type index. Make sure we
|
||||
# keep the record, or we'll have unbalanced scopes, which is bad. This situation
|
||||
# can arise when we can't find the type server PDB.
|
||||
|
||||
# RUN: yaml2obj %s -o %t.obj
|
||||
# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main
|
||||
# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
|
||||
|
||||
# CHECK: Mod 0000 | `{{.*}}pdb-invalid-func-type.yaml.tmp.obj`:
|
||||
# CHECK: 4 | S_GPROC32_ID [size = 44] `main`
|
||||
# CHECK: parent = 0, end = 80, addr = 0001:0000, code size = 3
|
||||
# CHECK: 48 | S_FRAMEPROC [size = 32]
|
||||
# CHECK: 80 | S_END [size = 4]
|
||||
|
||||
--- !COFF
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
Characteristics: [ ]
|
||||
sections:
|
||||
- Name: '.debug$S'
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
Subsections:
|
||||
- !Symbols
|
||||
Records:
|
||||
- Kind: S_GPROC32_ID
|
||||
ProcSym:
|
||||
CodeSize: 3
|
||||
DbgStart: 0
|
||||
DbgEnd: 2
|
||||
# Corrupt function type!
|
||||
FunctionType: 4101
|
||||
Flags: [ ]
|
||||
DisplayName: main
|
||||
- Kind: S_FRAMEPROC
|
||||
FrameProcSym:
|
||||
TotalFrameBytes: 0
|
||||
PaddingFrameBytes: 0
|
||||
OffsetToPadding: 0
|
||||
BytesOfCalleeSavedRegisters: 0
|
||||
OffsetOfExceptionHandler: 0
|
||||
SectionIdOfExceptionHandler: 0
|
||||
Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
|
||||
- Kind: S_PROC_ID_END
|
||||
ScopeEndSym:
|
||||
- !Lines
|
||||
CodeSize: 3
|
||||
Flags: [ ]
|
||||
RelocOffset: 0
|
||||
RelocSegment: 0
|
||||
Blocks:
|
||||
- FileName: 'c:\src\llvm-project\build\t.c'
|
||||
Lines:
|
||||
- Offset: 0
|
||||
LineStart: 1
|
||||
IsStatement: true
|
||||
EndDelta: 0
|
||||
Columns:
|
||||
- !FileChecksums
|
||||
Checksums:
|
||||
- FileName: 'c:\src\llvm-project\build\t.c'
|
||||
Kind: MD5
|
||||
Checksum: 270A878DCC1B845655B162F56C4F5020
|
||||
- !StringTable
|
||||
Strings:
|
||||
- 'c:\src\llvm-project\build\t.c'
|
||||
Relocations:
|
||||
- VirtualAddress: 44
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 48
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- VirtualAddress: 100
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECREL
|
||||
- VirtualAddress: 104
|
||||
SymbolName: main
|
||||
Type: IMAGE_REL_AMD64_SECTION
|
||||
- Name: '.debug$T'
|
||||
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 1
|
||||
Types:
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 0 ]
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 116
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 0
|
||||
ArgumentList: 4096
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4097
|
||||
Name: main
|
||||
- Name: '.text$mn'
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 16
|
||||
SectionData: 33C0C3
|
||||
symbols:
|
||||
- Name: '.debug$S'
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 328
|
||||
NumberOfRelocations: 4
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.debug$T'
|
||||
Value: 0
|
||||
SectionNumber: 2
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 564
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: '.text$mn'
|
||||
Value: 0
|
||||
SectionNumber: 3
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 3
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 4021952397
|
||||
Number: 0
|
||||
- Name: main
|
||||
Value: 0
|
||||
SectionNumber: 3
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
@ -13,12 +13,15 @@
|
||||
# CHECK-NEXT: Mod 0000 | Name: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`:
|
||||
# CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`:
|
||||
# CHECK-NEXT: debug stream: 9, # files: 0, has ec info: false
|
||||
# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
|
||||
# CHECK-NEXT: Mod 0001 | Name: `bar.obj`:
|
||||
# CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`:
|
||||
# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false
|
||||
# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
|
||||
# CHECK-NEXT: Mod 0002 | Name: `* Linker *`:
|
||||
# CHECK-NEXT: Obj: ``:
|
||||
# CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false
|
||||
# CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 ``
|
||||
|
||||
.def _main;
|
||||
.scl 2;
|
||||
|
18
test/COFF/pdb-linker-module.test
Normal file
18
test/COFF/pdb-linker-module.test
Normal file
@ -0,0 +1,18 @@
|
||||
RUN: lld-link /debug /pdb:%t.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj
|
||||
RUN: llvm-pdbutil dump -modules -symbols %t.pdb | FileCheck %s
|
||||
|
||||
CHECK: Mod 0001 | `* Linker *`:
|
||||
CHECK-NEXT: 4 | S_OBJNAME [size = 20] sig=0, `* Linker *`
|
||||
CHECK-NEXT: 24 | S_COMPILE3 [size = 40]
|
||||
CHECK-NEXT: machine = intel 80386, Ver = LLVM Linker, language = link
|
||||
CHECK-NEXT: frontend = 0.0.0.0, backend = 0.0.0.0
|
||||
CHECK-NEXT: flags = none
|
||||
CHECK-NEXT: 64 | S_ENVBLOCK
|
||||
CHECK-NEXT: - cwd
|
||||
CHECK-NEXT: -
|
||||
CHECK-NEXT: - exe
|
||||
CHECK-NEXT: - {{.*}}lld-link
|
||||
CHECK-NEXT: - pdb
|
||||
CHECK-NEXT: - {{.*}}pdb-linker-module{{.*}}pdb
|
||||
CHECK-NEXT: - cmd
|
||||
CHECK-NEXT: - /debug /pdb:{{.*}}pdb-linker-module{{.*}}pdb /nodefaultlib /entry:main {{.*}}pdb-diff.obj
|
@ -7,8 +7,8 @@
|
||||
|
||||
# CHECK: PdbStream:
|
||||
# CHECK-NEXT: Age: 0
|
||||
# CHECK-NEXT: Guid: '{00000000-0000-0000-0000-000000000000}'
|
||||
# CHECK-NEXT: Signature: 0
|
||||
# CHECK-NEXT: Guid:
|
||||
# CHECK-NEXT: Signature:
|
||||
# CHECK-NEXT: Features: [ VC140 ]
|
||||
# CHECK-NEXT: Version: VC70
|
||||
|
||||
|
75
test/COFF/pdb-scopes.test
Normal file
75
test/COFF/pdb-scopes.test
Normal file
@ -0,0 +1,75 @@
|
||||
Consider this program:
|
||||
|
||||
$ cat a.c
|
||||
void g(int x) {}
|
||||
void f(int x);
|
||||
int main(int argc) {
|
||||
if (argc) {
|
||||
int x = 42;
|
||||
f(x);
|
||||
} else {
|
||||
int y = 13;
|
||||
f(y);
|
||||
}
|
||||
}
|
||||
|
||||
$ cat b.c
|
||||
extern void g();
|
||||
void f(int x) {
|
||||
if (x) {
|
||||
int y = x + 3;
|
||||
g(y);
|
||||
} else {
|
||||
int w = x + 4;
|
||||
g(w);
|
||||
}
|
||||
}
|
||||
|
||||
This program is interesting because there are two TUs, and each TU has nested
|
||||
scopes. Make sure we get the right parent and end offsets.
|
||||
|
||||
RUN: yaml2obj %S/Inputs/pdb-scopes-a.yaml -o %t-a.obj
|
||||
RUN: yaml2obj %S/Inputs/pdb-scopes-b.yaml -o %t-b.obj
|
||||
RUN: lld-link %t-a.obj %t-b.obj -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb
|
||||
RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s
|
||||
|
||||
CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`:
|
||||
CHECK: 104 | S_GPROC32_ID [size = 44] `g`
|
||||
CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 5
|
||||
CHECK: debug start = 4, debug end = 4, flags = none
|
||||
CHECK: 180 | S_REGREL32 [size = 16] `x`
|
||||
CHECK: 196 | S_END [size = 4]
|
||||
CHECK: 200 | S_GPROC32_ID [size = 44] `main`
|
||||
CHECK: parent = 0, end = 384, addr = 0002:0016, code size = 58
|
||||
CHECK: debug start = 8, debug end = 53, flags = none
|
||||
CHECK: 276 | S_REGREL32 [size = 20] `argc`
|
||||
CHECK: 296 | S_BLOCK32 [size = 24] ``
|
||||
CHECK: parent = 200, end = 336
|
||||
CHECK: code size = 17, addr = 0002:0031
|
||||
CHECK: 320 | S_REGREL32 [size = 16] `x`
|
||||
CHECK: 336 | S_END [size = 4]
|
||||
CHECK: 340 | S_BLOCK32 [size = 24] ``
|
||||
CHECK: parent = 200, end = 380
|
||||
CHECK: code size = 17, addr = 0002:0050
|
||||
CHECK: 364 | S_REGREL32 [size = 16] `y`
|
||||
CHECK: 380 | S_END [size = 4]
|
||||
CHECK: 384 | S_END [size = 4]
|
||||
|
||||
CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`:
|
||||
CHECK: 104 | S_GPROC32_ID [size = 44] `f`
|
||||
CHECK: parent = 0, end = 284, addr = 0002:0080, code size = 62
|
||||
CHECK: debug start = 8, debug end = 57, flags = none
|
||||
CHECK: 180 | S_REGREL32 [size = 16] `x`
|
||||
CHECK: 196 | S_BLOCK32 [size = 24] ``
|
||||
CHECK: parent = 104, end = 236
|
||||
CHECK: code size = 20, addr = 0002:0095
|
||||
CHECK: 220 | S_REGREL32 [size = 16] `y`
|
||||
CHECK: 236 | S_END [size = 4]
|
||||
CHECK: 240 | S_BLOCK32 [size = 24] ``
|
||||
CHECK: parent = 104, end = 280
|
||||
CHECK: code size = 20, addr = 0002:0117
|
||||
CHECK: 264 | S_REGREL32 [size = 16] `w`
|
||||
CHECK: 280 | S_END [size = 4]
|
||||
CHECK: 284 | S_END [size = 4]
|
||||
|
||||
CHECK-LABEL: Mod 0002 | `* Linker *`:
|
@ -23,7 +23,7 @@ RUN: lld-link -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_li
|
||||
RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s
|
||||
|
||||
CHECK-LABEL: DbiStream:
|
||||
CHECK-NEXT: VerHeader: V110
|
||||
CHECK-NEXT: VerHeader: V70
|
||||
CHECK-NEXT: Age: 1
|
||||
CHECK-NEXT: BuildNumber: 0
|
||||
CHECK-NEXT: PdbDllVersion: 0
|
||||
|
@ -22,7 +22,7 @@
|
||||
# CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1
|
||||
# CHECK: flags = security checks | hot patchable
|
||||
# CHECK: 116 | S_GPROC32_ID [size = 44] `main`
|
||||
# CHECK: parent = 0, end = 0, addr = 0002:0000, code size = 7
|
||||
# CHECK: parent = 0, end = 192, addr = 0002:0000, code size = 7
|
||||
# CHECK: debug start = 0, debug end = 6, flags = none
|
||||
# CHECK: 160 | S_FRAMEPROC [size = 32]
|
||||
# CHECK: size = 0, padding size = 0, offset to padding = 0
|
||||
|
@ -26,11 +26,11 @@
|
||||
# CHECK: PdbStream:
|
||||
# CHECK-NEXT: Age: 1
|
||||
# CHECK-NEXT: Guid:
|
||||
# CHECK-NEXT: Signature: 0
|
||||
# CHECK-NEXT: Signature:
|
||||
# CHECK-NEXT: Features: [ VC140 ]
|
||||
# CHECK-NEXT: Version: VC70
|
||||
# CHECK-NEXT: DbiStream:
|
||||
# CHECK-NEXT: VerHeader: V110
|
||||
# CHECK-NEXT: VerHeader: V70
|
||||
# CHECK-NEXT: Age: 1
|
||||
# CHECK-NEXT: BuildNumber: 0
|
||||
# CHECK-NEXT: PdbDllVersion: 0
|
||||
@ -120,12 +120,15 @@ RAW-NEXT: ============================================================
|
||||
RAW-NEXT: Mod 0000 | Name: `{{.*}}pdb.test.tmp1.obj`:
|
||||
RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`:
|
||||
RAW-NEXT: debug stream: 9, # files: 1, has ec info: false
|
||||
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
|
||||
RAW-NEXT: Mod 0001 | Name: `{{.*}}pdb.test.tmp2.obj`:
|
||||
RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`:
|
||||
RAW-NEXT: debug stream: 10, # files: 1, has ec info: false
|
||||
RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
|
||||
RAW-NEXT: Mod 0002 | Name: `* Linker *`:
|
||||
RAW-NEXT: Obj: ``:
|
||||
RAW-NEXT: debug stream: 11, # files: 0, has ec info: false
|
||||
RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 ``
|
||||
RAW: Types (TPI Stream)
|
||||
RAW-NEXT: ============================================================
|
||||
RAW-NEXT: Showing 5 records
|
||||
@ -183,17 +186,17 @@ RAW-NEXT: IMAGE_SCN_MEM_READ
|
||||
RAW: Section Map
|
||||
RAW-NEXT: ============================================================
|
||||
RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 0, name = 1
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: flags = read | 32 bit addr | selector
|
||||
RAW-NEXT: Section 0001 | ovl = 1, group = 0, frame = 0, name = 2
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: flags = read | execute | 32 bit addr | selector
|
||||
RAW-NEXT: Section 0002 | ovl = 2, group = 0, frame = 0, name = 3
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: flags = read | 32 bit addr | selector
|
||||
RAW-NEXT: Section 0003 | ovl = 3, group = 0, frame = 0, name = 4
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: flags = read | 32 bit addr | selector
|
||||
RAW-NEXT: Section 0004 | ovl = 4, group = 0, frame = 0, name = 5
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: class = 65535, offset = 0, size =
|
||||
RAW-NEXT: flags = 32 bit addr | absolute addr
|
||||
|
3
test/ELF/Inputs/gnu-ifunc-dso.s
Normal file
3
test/ELF/Inputs/gnu-ifunc-dso.s
Normal file
@ -0,0 +1,3 @@
|
||||
.type foo STT_GNU_IFUNC
|
||||
.globl foo
|
||||
foo:
|
6
test/ELF/Inputs/symver-archive1.s
Normal file
6
test/ELF/Inputs/symver-archive1.s
Normal file
@ -0,0 +1,6 @@
|
||||
.text
|
||||
.globl x
|
||||
.type x, @function
|
||||
x:
|
||||
|
||||
.symver x, xx@@VER
|
1
test/ELF/Inputs/symver-archive2.s
Normal file
1
test/ELF/Inputs/symver-archive2.s
Normal file
@ -0,0 +1 @@
|
||||
call xx@PLT
|
1
test/ELF/Inputs/version-script-no-warn2.s
Normal file
1
test/ELF/Inputs/version-script-no-warn2.s
Normal file
@ -0,0 +1 @@
|
||||
call foo@plt
|
4
test/ELF/Inputs/version-script-weak.s
Normal file
4
test/ELF/Inputs/version-script-weak.s
Normal file
@ -0,0 +1,4 @@
|
||||
.text
|
||||
.globl foo
|
||||
.type foo,@function
|
||||
foo:
|
2
test/ELF/Inputs/wrap-dynamic-undef.s
Normal file
2
test/ELF/Inputs/wrap-dynamic-undef.s
Normal file
@ -0,0 +1,2 @@
|
||||
.global foo
|
||||
foo:
|
@ -26,14 +26,9 @@ _start:
|
||||
.section .R_ARM_MOVT_ABS, "ax",%progbits
|
||||
movt r0, :upper16:label
|
||||
movt r1, :upper16:label1
|
||||
// FIXME: We shouldn't need to multiply by 65536.
|
||||
// arguably llvm-mc incorrectly assembles addends for
|
||||
// SHT_REL relocated movt instructions. When there is a relocation
|
||||
// the interpretation of the addend for SHT_REL is not shifted
|
||||
movt r2, :upper16:label2 + (4 * 65536)
|
||||
movt r2, :upper16:label2 + 4
|
||||
movt r3, :upper16:label3
|
||||
// FIXME: We shouldn't need to multiply by 65536 see comment above.
|
||||
movt r4, :upper16:label3 + (4 * 65536)
|
||||
movt r4, :upper16:label3 + 4
|
||||
// CHECK: Disassembly of section .R_ARM_MOVT_ABS
|
||||
// CHECK: movt r0, #2
|
||||
// CHECK: movt r1, #2
|
||||
|
@ -4,7 +4,7 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
|
||||
// RUN: not ld.lld %t2.o %t1.so -o %t2.so -shared 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo
|
||||
// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment
|
||||
// CHECK: >>> defined in {{.*}}.so
|
||||
// CHECK: >>> referenced by {{.*}}.o:(.text+0x0)
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
# CHECK-NEXT: Section: Absolute
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: foo2
|
||||
# CHECK-NEXT: Name: foo1
|
||||
# CHECK-NEXT: Value: 0x123
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Global
|
||||
|
10
test/ELF/duplicated-synthetic-sym.s
Normal file
10
test/ELF/duplicated-synthetic-sym.s
Normal file
@ -0,0 +1,10 @@
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
// RUN: cd %S
|
||||
// RUN: not ld.lld %t.o --format=binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: duplicate symbol: _binary_duplicated_synthetic_sym_s_start
|
||||
// CHECK: defined at (internal):(.data+0x0)
|
||||
|
||||
.globl _binary_duplicated_synthetic_sym_s_start
|
||||
_binary_duplicated_synthetic_sym_s_start:
|
||||
.long 0
|
13
test/ELF/gnu-ifunc-dso.s
Normal file
13
test/ELF/gnu-ifunc-dso.s
Normal file
@ -0,0 +1,13 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-dso.s -o %t1.o
|
||||
# RUN: ld.lld -shared %t1.o -o %t.so
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
|
||||
# RUN: ld.lld -shared %t2.o %t.so -o %t
|
||||
# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
|
||||
|
||||
# CHECK: Dynamic Relocations {
|
||||
# CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0
|
||||
# CHECK-NEXT: }
|
||||
|
||||
.data
|
||||
.quad foo
|
Binary file not shown.
41
test/ELF/invalid/invalid-debug-relocations.test
Normal file
41
test/ELF/invalid/invalid-debug-relocations.test
Normal file
@ -0,0 +1,41 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: yaml2obj %s -o %t.o
|
||||
# RUN: not ld.lld -gdb-index %t.o -o %t.exe 2>&1 | FileCheck %s
|
||||
|
||||
# CHECK: error: {{.*}}.o: error parsing DWARF data:
|
||||
# CHECK-NEXT: >>> failed to compute relocation: Unknown, Invalid data was encountered while parsing the file
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_386
|
||||
Sections:
|
||||
- Type: SHT_PROGBITS
|
||||
Name: .text
|
||||
Flags: [ ]
|
||||
AddressAlign: 0x04
|
||||
Content: "0000"
|
||||
- Type: SHT_PROGBITS
|
||||
Name: .debug_info
|
||||
Flags: [ ]
|
||||
AddressAlign: 0x04
|
||||
Content: "0000"
|
||||
- Type: SHT_REL
|
||||
Name: .rel.debug_info
|
||||
Link: .symtab
|
||||
Info: .debug_info
|
||||
Relocations:
|
||||
- Offset: 0
|
||||
Symbol: _start
|
||||
Type: 0xFF
|
||||
- Offset: 4
|
||||
Symbol: _start
|
||||
Type: 0xFF
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: _start
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x0
|
@ -1,7 +1,8 @@
|
||||
## invalid-relocation-x64.elf contains relocations with invalid relocation number.
|
||||
## Next yaml code was used to create initial binary. After that it
|
||||
## was modified with hex-editor to replace known relocations with fake ones,
|
||||
## that have 0x98 and 0x98 numbers.
|
||||
# RUN: yaml2obj %s -o %t.o
|
||||
# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
|
||||
# CHECK: {{.*}}.o: unknown relocation type: Unknown (152)
|
||||
# CHECK: {{.*}}.o: unknown relocation type: Unknown (153)
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
@ -20,11 +21,7 @@ Sections:
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000000
|
||||
Symbol: ''
|
||||
Type: R_X86_64_NONE
|
||||
Type: 0x98
|
||||
- Offset: 0x0000000000000000
|
||||
Symbol: ''
|
||||
Type: R_X86_64_NONE
|
||||
|
||||
# RUN: not ld.lld %p/Inputs/invalid-relocation-x64.elf -o %t2 2>&1 | FileCheck %s
|
||||
# CHECK: {{.*}}invalid-relocation-x64.elf: unknown relocation type: Unknown (152)
|
||||
# CHECK: {{.*}}invalid-relocation-x64.elf: unknown relocation type: Unknown (153)
|
||||
Type: 0x99
|
||||
|
@ -2,8 +2,10 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
# RUN: echo "SECTIONS {" > %t.script
|
||||
# RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script
|
||||
# RUN: not ld.lld %t.o --script %t.script -o %t -shared 2>&1 | FileCheck %s
|
||||
# CHECK: {{.*}}.script:2: unable to move location counter backward
|
||||
# RUN: ld.lld %t.o --script %t.script -o %t -shared
|
||||
# RUN: llvm-objdump -section-headers %t | FileCheck %s
|
||||
# CHECK: Idx Name Size Address
|
||||
# CHECK: 1 .text 00000000 0000000000000010
|
||||
|
||||
# RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script
|
||||
# RUN: ld.lld %t.o --script %t2.script -o %t -shared
|
||||
|
44
test/ELF/linkerscript/non-alloc-segment.s
Normal file
44
test/ELF/linkerscript/non-alloc-segment.s
Normal file
@ -0,0 +1,44 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
|
||||
################################################################################
|
||||
## Test that non-alloc section .foo can be assigned to a segment. Check that
|
||||
## the values of the offset and file size of this segment's PHDR are correct.
|
||||
##
|
||||
## This functionality allows non-alloc metadata, which is not required at
|
||||
## run-time, to be added to a custom segment in a file. This metadata may be
|
||||
## read/edited by tools/loader using the values of the offset and file size from
|
||||
## the custom segment's PHDR. This is particularly important if section headers
|
||||
## have been stripped.
|
||||
# RUN: echo "PHDRS {text PT_LOAD; foo 0x12345678;} \
|
||||
# RUN: SECTIONS { \
|
||||
# RUN: .text : {*(.text .text*)} :text \
|
||||
# RUN: .foo : {*(.foo)} :foo \
|
||||
# RUN: }" > %t.script
|
||||
# RUN: ld.lld -o %t --script %t.script %t.o
|
||||
# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s
|
||||
# RUN: llvm-readobj -l %t | FileCheck --check-prefix=PHDR %s
|
||||
|
||||
# CHECK: Program Headers:
|
||||
# CHECK-NEXT: Type
|
||||
# CHECK-NEXT: LOAD
|
||||
# CHECK-NEXT: <unknown>: 0x12345678
|
||||
|
||||
# CHECK: Section to Segment mapping:
|
||||
# CHECK-NEXT: Segment Sections...
|
||||
# CHECK-NEXT: 00 .text
|
||||
# CHECK-NEXT: 01 .foo
|
||||
|
||||
# PHDR: Type: (0x12345678)
|
||||
# PHDR-NEXT: Offset: 0x1004
|
||||
# PHDR-NEXT: VirtualAddress
|
||||
# PHDR-NEXT: PhysicalAddress
|
||||
# PHDR-NEXT: FileSize: 4
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
nop
|
||||
|
||||
.section .foo
|
||||
.align 4
|
||||
.long 0
|
@ -1,9 +1,18 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o
|
||||
# RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script
|
||||
# RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s
|
||||
# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
|
||||
# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
|
||||
|
||||
# CHECK: error: {{.*}}.script:1: unable to move location counter backward
|
||||
# CHECK: Sections:
|
||||
# CHECK-NEXT: Idx Name Size Address Type
|
||||
# CHECK-NEXT: 0 00000000 0000000000000000
|
||||
# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA
|
||||
# CHECK-NEXT: 2 .dynamic 00000060 0000000000004008
|
||||
# CHECK-NEXT: 3 .text 00000008 0000000000002000 TEXT DATA
|
||||
# CHECK-NEXT: 4 .dynsym 00000018 0000000000002008
|
||||
# CHECK-NEXT: 5 .hash 00000010 0000000000002020
|
||||
# CHECK-NEXT: 6 .dynstr 00000001 0000000000002030
|
||||
|
||||
.quad 0
|
||||
.data
|
||||
|
18
test/ELF/linkerscript/unused-synthetic.s
Normal file
18
test/ELF/linkerscript/unused-synthetic.s
Normal file
@ -0,0 +1,18 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
# RUN: echo "SECTIONS { \
|
||||
# RUN: .got : { *(.got) } \
|
||||
# RUN: .plt : { *(.plt) } \
|
||||
# RUN: .text : { *(.text) } \
|
||||
# RUN: }" > %t.script
|
||||
# RUN: ld.lld -shared -o %t.so --script %t.script %t.o
|
||||
|
||||
# RUN: llvm-objdump -section-headers %t.so | FileCheck %s
|
||||
# CHECK-NOT: .got
|
||||
# CHECK-NOT: .plt
|
||||
# CHECK: .text
|
||||
# CHECK-NEXT: .dynsym
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
nop
|
@ -1,9 +1,16 @@
|
||||
; REQUIRES: x86
|
||||
; LTO
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o
|
||||
; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
|
||||
; RUN: llvm-objdump -d %t.so | FileCheck %s
|
||||
|
||||
; ThinLTO
|
||||
; RUN: opt -module-summary %s -o %t.o
|
||||
; RUN: opt -module-summary %S/Inputs/defsym-bar.ll -o %t1.o
|
||||
; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3
|
||||
; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=THIN
|
||||
|
||||
; Call to bar2() should not be inlined and should be routed to bar3()
|
||||
; Symbol bar3 should not be eliminated
|
||||
|
||||
@ -13,6 +20,13 @@
|
||||
; CHECK-NEXT: callq{{.*}}<bar3>
|
||||
; CHECK-NEXT: callq
|
||||
|
||||
; THIN: foo
|
||||
; THIN-NEXT: pushq %rax
|
||||
; THIN-NEXT: callq
|
||||
; THIN-NEXT: callq{{.*}}<bar3>
|
||||
; THIN-NEXT: popq %rax
|
||||
; THIN-NEXT: jmp
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
|
@ -1,9 +1,16 @@
|
||||
; REQUIRES: x86
|
||||
; LTO
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps
|
||||
; RUN: llvm-readobj -t %t.out | FileCheck %s
|
||||
; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s
|
||||
|
||||
; ThinLTO
|
||||
; RUN: opt -module-summary %s -o %t.o
|
||||
; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps
|
||||
; RUN: llvm-readobj -t %t.out | FileCheck %s
|
||||
; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s
|
||||
|
||||
; CHECK: Name: __wrap_bar
|
||||
; CHECK-NEXT: Value:
|
||||
; CHECK-NEXT: Size:
|
||||
|
@ -1,17 +1,31 @@
|
||||
; REQUIRES: x86
|
||||
; LTO
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o
|
||||
; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar
|
||||
; RUN: llvm-objdump -d %t.so | FileCheck %s
|
||||
; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s
|
||||
|
||||
; ThinLTO
|
||||
; RUN: opt -module-summary %s -o %t.o
|
||||
; RUN: opt -module-summary %S/Inputs/wrap-bar.ll -o %t1.o
|
||||
; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar
|
||||
; RUN: llvm-objdump -d %t.so | FileCheck %s -check-prefix=THIN
|
||||
; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s
|
||||
|
||||
; Make sure that calls in foo() are not eliminated and that bar is
|
||||
; routed to __wrap_bar and __real_bar is routed to bar.
|
||||
|
||||
; CHECK: foo:
|
||||
; CHECK-NEXT: pushq %rax
|
||||
; CHECK-NEXT: callq{{.*}}<__wrap_bar>
|
||||
; CHECK-NEXT: callq{{.*}}<bar>
|
||||
; CHECK-NEXT: callq{{.*}}<__real_bar>
|
||||
|
||||
; THIN: foo:
|
||||
; THIN-NEXT: pushq %rax
|
||||
; THIN-NEXT: callq{{.*}}<__wrap_bar>
|
||||
; THIN-NEXT: popq %rax
|
||||
; THIN-NEXT: jmp{{.*}}<bar>
|
||||
|
||||
; Check that bar and __wrap_bar retain their original binding.
|
||||
; BIND: Name: bar
|
||||
|
15
test/ELF/symver-archive.s
Normal file
15
test/ELF/symver-archive.s
Normal file
@ -0,0 +1,15 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-ar rcs %t.a %t1
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o
|
||||
# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a
|
||||
|
||||
.text
|
||||
.globl x
|
||||
.type x, @function
|
||||
x:
|
||||
|
||||
.globl xx
|
||||
xx = x
|
8
test/ELF/version-script-no-warn2.s
Normal file
8
test/ELF/version-script-no-warn2.s
Normal file
@ -0,0 +1,8 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/version-script-no-warn2.s -o %t1.o
|
||||
# RUN: ld.lld %t1.o -o %t1.so -shared
|
||||
# RUN: echo "{ global: foo; local: *; };" > %t.script
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
|
||||
# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o %t2.so --fatal-warnings
|
||||
|
||||
.global foo
|
||||
foo:
|
@ -1,8 +1,6 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
# RUN: echo "VERSION { global: *; };" > %t.map
|
||||
# RUN: ld.lld %t.o --version-script %t.map -o %t
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
|
||||
.global _start
|
||||
.global bar
|
||||
|
28
test/ELF/version-script-symver2.s
Normal file
28
test/ELF/version-script-symver2.s
Normal file
@ -0,0 +1,28 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
# RUN: echo "VER1 { global: foo; local: *; }; VER2 { global: foo; }; VER3 { global: foo; };" > %t.map
|
||||
# RUN: ld.lld -shared %t.o --version-script %t.map -o %t.so --fatal-warnings
|
||||
# RUN: llvm-readobj -V %t.so | FileCheck %s
|
||||
|
||||
# CHECK: Symbols [
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: Name: @
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Version: 3
|
||||
# CHECK-NEXT: Name: foo@@VER2
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Version: 2
|
||||
# CHECK-NEXT: Name: foo@VER1
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
.global bar
|
||||
bar:
|
||||
.symver bar, foo@VER1
|
||||
|
||||
.global zed
|
||||
zed:
|
||||
.symver zed, foo@@VER2
|
12
test/ELF/version-script-undef-version.s
Normal file
12
test/ELF/version-script-undef-version.s
Normal file
@ -0,0 +1,12 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# Test that we don't error on undefined versions when static linking.
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t
|
||||
# RUN: echo "DEFINED { global: *; };" > %t.map
|
||||
# RUN: ld.lld %t.o --version-script %t.map -o %t
|
||||
|
||||
.global _start
|
||||
.global bar
|
||||
.symver _start, bar@@UNDEFINED
|
||||
_start:
|
28
test/ELF/version-script-weak.s
Normal file
28
test/ELF/version-script-weak.s
Normal file
@ -0,0 +1,28 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/version-script-weak.s -o %tmp.o
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-ar rcs %t.a %tmp.o
|
||||
# RUN: echo "{ local: *; };" > %t.script
|
||||
# RUN: ld.lld -shared --version-script %t.script %t.o %t.a -o %t.so
|
||||
# RUN: llvm-readobj -dyn-symbols -r %t.so | FileCheck %s
|
||||
|
||||
# CHECK: Relocations [
|
||||
# CHECK-NEXT: Section ({{.*}}) .rela.plt {
|
||||
# CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: foo@
|
||||
# CHECK-NEXT: Value: 0x0
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Weak
|
||||
# CHECK-NEXT: Type: None
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: Undefined
|
||||
# CHECK-NEXT: }
|
||||
|
||||
.text
|
||||
callq foo@PLT
|
||||
.weak foo
|
15
test/ELF/wrap-dynamic-undef.s
Normal file
15
test/ELF/wrap-dynamic-undef.s
Normal file
@ -0,0 +1,15 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap-dynamic-undef.s -o %t2.o
|
||||
# RUN: ld.lld %t2.o -o %t2.so -shared
|
||||
# RUN: ld.lld %t1.o %t2.so -o %t --wrap foo
|
||||
# RUN: llvm-readobj -dyn-symbols --elf-output-style=GNU %t | FileCheck %s
|
||||
|
||||
# Test that the dynamic relocation uses foo. We used to produce a
|
||||
# relocation with __real_foo.
|
||||
|
||||
# CHECK: NOTYPE GLOBAL DEFAULT UND foo
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
callq __real_foo@plt
|
@ -12,12 +12,16 @@
|
||||
// CHECK-NEXT: movl $0x11010, %edx
|
||||
// CHECK-NEXT: movl $0x11000, %edx
|
||||
|
||||
// This shows an oddity of our implementation. The symbol foo gets
|
||||
// mapped to __wrap_foo, but stays in the symbol table. This results
|
||||
// in it showing up twice in the output.
|
||||
|
||||
// RUN: llvm-readobj -t -s %t3 | FileCheck -check-prefix=SYM %s
|
||||
// SYM: Name: __real_foo
|
||||
// SYM: Name: foo
|
||||
// SYM-NEXT: Value: 0x11000
|
||||
// SYM: Name: __wrap_foo
|
||||
// SYM-NEXT: Value: 0x11010
|
||||
// SYM: Name: foo
|
||||
// SYM: Name: __wrap_foo
|
||||
// SYM-NEXT: Value: 0x11010
|
||||
|
||||
.global _start
|
||||
|
@ -122,8 +122,8 @@ if config.test_exec_root is None:
|
||||
lit_config.fatal('No site specific configuration available!')
|
||||
|
||||
# Get the source and object roots.
|
||||
llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
|
||||
llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
|
||||
llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip()
|
||||
llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip()
|
||||
lld_src_root = os.path.join(llvm_src_root, "tools", "lld")
|
||||
lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user