[PECOFF] Create __ImageBase symbol.

__ImageBase is a symbol having 4 byte integer equal to the image base address
of the resultant executable. The linker is expected to create the symbol as if
it were read from a file.

In order to emit the symbol contents only when the symbol is actually
referenced, we created a pseudo library file to wrap the linker generated
symbol. The library file member is emitted to the output only when the member
is actually referenced, which is suitable for our purpose.

llvm-svn: 188052
This commit is contained in:
Rui Ueyama 2013-08-09 04:44:15 +00:00
parent 0ecb26a79e
commit 908606d0a9
4 changed files with 203 additions and 20 deletions

View File

@ -0,0 +1,128 @@
//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp --------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Atoms.h"
#include "GroupedSectionsPass.h"
#include "IdataPass.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Path.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/InputFiles.h"
#include "lld/Core/PassManager.h"
#include "lld/Passes/LayoutPass.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Simple.h"
#include "lld/ReaderWriter/Writer.h"
namespace lld {
namespace coff {
namespace {
// The symbol ___ImageBase is a linker generated symbol. No standard library
// files define it, but the linker is expected to prepare it as if it was read
// from a file. The content of the atom is a 4-byte integer equal to the image
// base address.
class ImageBaseAtom : public COFFLinkerInternalAtom {
public:
ImageBaseAtom(const File &file, uint32_t imageBase)
: COFFLinkerInternalAtom(file, assembleRawContent(imageBase)) {}
virtual StringRef name() const { return "___ImageBase"; }
virtual uint64_t ordinal() const { return 0; }
virtual ContentType contentType() const { return typeData; }
virtual ContentPermissions permissions() const { return permRW_; }
virtual DeadStripKind deadStrip() const { return deadStripAlways; }
private:
std::vector<uint8_t> assembleRawContent(uint32_t imageBase) {
std::vector<uint8_t> data = std::vector<uint8_t>(4);
*(reinterpret_cast<uint32_t *>(&data[0])) = imageBase;
return data;
}
};
// The file to wrap ImageBaseAtom. This is the only member file of
// LinkerGeneratedSymbolFile.
class MemberFile : public SimpleFile {
public:
MemberFile(const PECOFFLinkingContext &context)
: SimpleFile(context, "Member of the Linker Internal File"),
_atom(*this, context.getBaseAddress()) {
addAtom(_atom);
};
private:
ImageBaseAtom _atom;
};
} // anonymous namespace
// A pseudo library file to wrap MemberFile, which in turn wraps ImageBaseAtom.
// The file the core linker handle is this.
//
// The reason why we don't pass MemberFile to the core linker is because, if we
// did so, ImageBaseAtom would always be emit to the resultant executable. By
// wrapping the file by a library file, we made it to emit ImageBaseAtom only
// when the atom is really referenced.
class LinkerGeneratedSymbolFile : public ArchiveLibraryFile {
public:
LinkerGeneratedSymbolFile(const PECOFFLinkingContext &context)
: ArchiveLibraryFile(context, "Linker Internal File"),
_memberFile(context) {};
virtual const File *find(StringRef name, bool dataSymbolOnly) const {
if (name == "___ImageBase")
return &_memberFile;
return nullptr;
}
virtual const atom_collection<DefinedAtom> &defined() const {
return _noDefinedAtoms;
}
virtual const atom_collection<UndefinedAtom> &undefined() const {
return _noUndefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
return _noSharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom> &absolute() const {
return _noAbsoluteAtoms;
}
private:
MemberFile _memberFile;
};
/// An instance of UndefinedSymbolFile has a list of undefined symbols
/// specified by "/include" command line option. This will be added to the
/// input file list to force the core linker to try to resolve the undefined
/// symbols.
class UndefinedSymbolFile : public SimpleFile {
public:
UndefinedSymbolFile(const LinkingContext &ti)
: SimpleFile(ti, "Linker Internal File") {
for (StringRef symbol : ti.initialUndefinedSymbols()) {
UndefinedAtom *atom = new (_alloc) coff::COFFUndefinedAtom(*this, symbol);
addAtom(*atom);
}
}
private:
llvm::BumpPtrAllocator _alloc;
};
} // end namespace coff
} // end namespace lld

View File

@ -10,6 +10,7 @@
#include "Atoms.h"
#include "GroupedSectionsPass.h"
#include "IdataPass.h"
#include "LinkerGeneratedSymbolFile.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Allocator.h"
@ -30,24 +31,6 @@ bool containDirectoryName(StringRef path) {
llvm::sys::path::remove_filename(smallStr);
return !smallStr.str().empty();
}
/// An instance of UndefinedSymbolFile has a list of undefined symbols
/// specified by "/include" command line option. This will be added to the
/// input file list to force the core linker to try to resolve the undefined
/// symbols.
class UndefinedSymbolFile : public SimpleFile {
public:
UndefinedSymbolFile(const LinkingContext &ti)
: SimpleFile(ti, "Linker Internal File") {
for (StringRef symbol : ti.initialUndefinedSymbols()) {
UndefinedAtom *atom = new (_alloc) coff::COFFUndefinedAtom(*this, symbol);
addAtom(*atom);
}
}
private:
llvm::BumpPtrAllocator _alloc;
};
} // anonymous namespace
error_code PECOFFLinkingContext::parseFile(
@ -83,8 +66,11 @@ bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
void PECOFFLinkingContext::addImplicitFiles(InputFiles &files) const {
// Add a pseudo file for "/include" linker option.
auto *file = new (_alloc) UndefinedSymbolFile(*this);
files.prependFile(*file);
auto *undefFile = new (_alloc) coff::UndefinedSymbolFile(*this);
files.prependFile(*undefFile);
auto *linkerFile = new (_alloc) coff::LinkerGeneratedSymbolFile(*this);
files.appendFile(*linkerFile);
}
/// Append the given file to the input file list. The file must be an object

View File

@ -0,0 +1,59 @@
---
header:
Machine: IMAGE_FILE_MACHINE_I386
Characteristics: [ ]
sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: A100000000C3
Relocations:
- VirtualAddress: 1
SymbolName: ___ImageBase
Type: IMAGE_REL_I386_DIR32
- Name: .data
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
Alignment: 16
SectionData: ""
- Name: .drectve
Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
Alignment: 2147483648
SectionData: 2F454E5452593A5F737461727420
symbols:
- Name: .text
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
NumberOfAuxSymbols: 1
AuxiliaryData: 060000000100000000000000000000000000
- Name: .data
Value: 0
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
NumberOfAuxSymbols: 1
AuxiliaryData: 000000000000000000000000000000000000
- Name: ___ImageBase
Value: 0
SectionNumber: 0
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: __start
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: .drectve
Value: 0
SectionNumber: 3
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
NumberOfAuxSymbols: 1
AuxiliaryData: 0E0000000000000000000000000000000000
...

View File

@ -0,0 +1,10 @@
# RUN: yaml2obj %p/Inputs/imagebase.obj.yaml > %t.obj
#
# RUN: lld -flavor link /out:%t1 /subsystem:console -- %t.obj \
# RUN: && llvm-objdump -disassemble %t1 | FileCheck -check-prefix=CHECK1 %s
#
# RUN: lld -flavor link /out:%t1 /subsystem:console /base:65536 -- %t.obj \
# RUN: && llvm-objdump -disassemble %t1 | FileCheck -check-prefix=CHECK2 %s
CHECK1: a1 00 20 40 00 movl 4202496, %eax
CHECK2: a1 00 20 01 00 movl 73728, %eax