1
0
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:
Dimitry Andric 2017-07-13 19:26:06 +00:00
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
85 changed files with 2668 additions and 494 deletions

View File

@ -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());
}

View File

@ -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 {

View File

@ -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;

View File

@ -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>();

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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>();
}
};
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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};
}
}

View File

@ -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>;

View File

@ -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,

View File

@ -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;
}

View 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);

View File

@ -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.

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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);

Binary file not shown.

Binary file not shown.

View 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; }

Binary file not shown.

View 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
...

View 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
...

View 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
...

View 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
...

View File

@ -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: )

View File

@ -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
View 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: |----------------------------------------+---|

View 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
...

View File

@ -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;

View 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

View File

@ -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
View 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 *`:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
.type foo STT_GNU_IFUNC
.globl foo
foo:

View File

@ -0,0 +1,6 @@
.text
.globl x
.type x, @function
x:
.symver x, xx@@VER

View File

@ -0,0 +1 @@
call xx@PLT

View File

@ -0,0 +1 @@
call foo@plt

View File

@ -0,0 +1,4 @@
.text
.globl foo
.type foo,@function
foo:

View File

@ -0,0 +1,2 @@
.global foo
foo:

View File

@ -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

View File

@ -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)

View File

@ -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

View 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
View 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

View 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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View 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

View File

@ -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"

View File

@ -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:

View File

@ -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
View 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

View 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:

View File

@ -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

View 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

View 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:

View 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

View 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

View File

@ -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

View File

@ -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")