[PECOFF] Implement IMAGE_REL_I386_{SECTION,SECREL} relocations.

These relocations are used in .debug section.

llvm-svn: 196262
This commit is contained in:
Rui Ueyama 2013-12-03 09:18:31 +00:00
parent 14b02848a3
commit fac7332d71
4 changed files with 67 additions and 46 deletions

View File

@ -180,6 +180,8 @@ PECOFFLinkingContext::relocKindFromString(StringRef str) const {
LLD_CASE(IMAGE_REL_I386_ABSOLUTE)
LLD_CASE(IMAGE_REL_I386_DIR32)
LLD_CASE(IMAGE_REL_I386_DIR32NB)
LLD_CASE(IMAGE_REL_I386_SECTION)
LLD_CASE(IMAGE_REL_I386_SECREL)
LLD_CASE(IMAGE_REL_I386_REL32)
.Default(-1);
#undef LLD_CASE
@ -198,6 +200,8 @@ PECOFFLinkingContext::stringFromRelocKind(Reference::Kind kind) const {
LLD_CASE(IMAGE_REL_I386_ABSOLUTE)
LLD_CASE(IMAGE_REL_I386_DIR32)
LLD_CASE(IMAGE_REL_I386_DIR32NB)
LLD_CASE(IMAGE_REL_I386_SECTION)
LLD_CASE(IMAGE_REL_I386_SECREL)
LLD_CASE(IMAGE_REL_I386_REL32)
#undef LLD_CASE
}

View File

@ -195,6 +195,7 @@ public:
void applyRelocations(uint8_t *fileBuffer,
std::map<const Atom *, uint64_t> &atomRva,
std::vector<uint64_t> &sectionRva,
uint64_t imageBaseAddress);
void printAtomAddresses(uint64_t baseAddr);
void addBaseRelocations(std::vector<uint64_t> &relocSites);
@ -505,16 +506,18 @@ void AtomChunk::write(uint8_t *fileBuffer) {
void AtomChunk::applyRelocations(uint8_t *fileBuffer,
std::map<const Atom *, uint64_t> &atomRva,
std::vector<uint64_t> &sectionRva,
uint64_t imageBaseAddress) {
for (const auto *layout : _atomLayouts) {
const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
for (const Reference *ref : *atom) {
auto relocSite = reinterpret_cast<ulittle32_t *>(
auto relocSite32 = reinterpret_cast<ulittle32_t *>(
fileBuffer + layout->_fileOffset + ref->offsetInAtom());
auto relocSite16 = reinterpret_cast<ulittle16_t *>(relocSite32);
uint64_t targetAddr = atomRva[ref->target()];
// Also account for whatever offset is already stored at the relocation
// site.
targetAddr += *relocSite;
targetAddr += *relocSite32;
// Skip if this reference is not for relocation.
if (ref->kind() < lld::Reference::kindTargetLow)
@ -526,19 +529,42 @@ void AtomChunk::applyRelocations(uint8_t *fileBuffer,
break;
case llvm::COFF::IMAGE_REL_I386_DIR32:
// Set target's 32-bit VA.
*relocSite = targetAddr + imageBaseAddress;
*relocSite32 = targetAddr + imageBaseAddress;
break;
case llvm::COFF::IMAGE_REL_I386_DIR32NB:
// Set target's 32-bit RVA.
*relocSite = targetAddr;
*relocSite32 = targetAddr;
break;
case llvm::COFF::IMAGE_REL_I386_REL32: {
// Set 32-bit relative address of the target. This relocation is
// usually used for relative branch or call instruction.
uint32_t disp = atomRva[atom] + ref->offsetInAtom() + 4;
*relocSite = targetAddr - disp;
*relocSite32 = targetAddr - disp;
break;
}
case llvm::COFF::IMAGE_REL_I386_SECTION: {
// The 16-bit section index that contains the target symbol.
uint16_t i = 1;
for (uint64_t rva : sectionRva) {
if (targetAddr < rva) {
*relocSite16 = i;
break;
}
++i;
}
break;
}
case llvm::COFF::IMAGE_REL_I386_SECREL:
// The 32-bit relative address from the beginning of the section that
// contains the target symbol.
for (int i = 0, e = sectionRva.size(); i < e; ++i) {
if (i == e - 1 ||
(sectionRva[i] <= targetAddr && targetAddr <= sectionRva[i + 1])) {
*relocSite32 = targetAddr - sectionRva[i];
break;
}
}
break;
default:
llvm_unreachable("Unsupported relocation kind");
}
@ -860,6 +886,9 @@ private:
// The map from defined atoms to its RVAs. Will be used for relocation.
std::map<const Atom *, uint64_t> atomRva;
// List of section RVAs. Will be used for relocation.
std::vector<uint64_t> sectionRva;
};
StringRef customSectionName(const DefinedAtom *atom) {
@ -930,11 +959,13 @@ void ExecutableWriter::build(const File &linkedFile) {
SectionChunk *text = nullptr;
SectionChunk *data = nullptr;
std::vector<SectionChunk *> sectionChunks;
for (auto i : atoms) {
StringRef sectionName = i.first;
std::vector<const DefinedAtom *> &contents = i.second;
auto *section = new GenericSectionChunk(_PECOFFLinkingContext, sectionName,
contents);
sectionChunks.push_back(section);
addSectionChunk(section, sectionTable);
if (!text && sectionName == ".text")
@ -961,6 +992,9 @@ void ExecutableWriter::build(const File &linkedFile) {
setImageSizeOnDisk();
for (SectionChunk *p : sectionChunks)
sectionRva.push_back(p->getVirtualAddress());
// Now that we know the size and file offset of sections. Set the file
// header accordingly.
peHeader->setSizeOfCode(calcSizeOfCode());
@ -1005,7 +1039,7 @@ error_code ExecutableWriter::writeFile(const File &linkedFile, StringRef path) {
void ExecutableWriter::applyAllRelocations(uint8_t *bufferStart) {
for (auto &cp : _chunks)
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
chunk->applyRelocations(bufferStart, atomRva,
chunk->applyRelocations(bufferStart, atomRva, sectionRva,
_PECOFFLinkingContext.getBaseAddress());
}

View File

@ -6,15 +6,21 @@ sections:
- Name: .text
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
Alignment: 16
SectionData: 5589E583EC14C745FC00000000C744240C00000000C744240807000000C744240400000000C7042400000000FF150000000083EC1031C083C4145DC3
SectionData: 68000000006800000000680000000068000000006800000000
Relocations:
- VirtualAddress: 25
- VirtualAddress: 1
SymbolName: _message
Type: IMAGE_REL_I386_SECTION
- VirtualAddress: 6
SymbolName: _message
Type: IMAGE_REL_I386_SECREL
- VirtualAddress: 11
SymbolName: .data
Type: IMAGE_REL_I386_DIR32
- VirtualAddress: 33
- VirtualAddress: 16
SymbolName: .data
Type: IMAGE_REL_I386_DIR32
- VirtualAddress: 46
- VirtualAddress: 21
SymbolName: __imp__MessageBoxA@16
Type: IMAGE_REL_I386_DIR32
- Name: .data
@ -44,6 +50,12 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
- Name: _message
Value: 5
SectionNumber: 2
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_STATIC
- Name: __imp__MessageBoxA@16
Value: 0
SectionNumber: 0

View File

@ -1,40 +1,11 @@
# RUN: yaml2obj %p/Inputs/reloc.obj.yaml > %t.obj
#
# RUN: llvm-objdump -d %t.obj | FileCheck -check-prefix=BEFORE %s
#
# RUN: lld -flavor link /out:%t1 /subsystem:console /force /opt:noref \
# RUN: -- %t.obj && llvm-objdump -d %t1 | FileCheck -check-prefix=AFTER %s
# RUN: -- %t.obj && llvm-objdump -d %t1 | FileCheck %s
BEFORE: Disassembly of section .text:
BEFORE: _main:
BEFORE: 0: 55
BEFORE: 1: 89 e5
BEFORE: 3: 83 ec 14
BEFORE: 6: c7 45 fc 00 00 00 00
BEFORE: d: c7 44 24 0c 00 00 00 00
BEFORE: 15: c7 44 24 08 07 00 00 00
BEFORE: 1d: c7 44 24 04 00 00 00 00
BEFORE: 25: c7 04 24 00 00 00 00
BEFORE: 2c: ff 15 00 00 00 00
BEFORE: 32: 83 ec 10
BEFORE: 35: 31 c0
BEFORE: 37: 83 c4 14
BEFORE: 3a: 5d
BEFORE: 3b: c3
AFTER: Disassembly of section .text:
AFTER: .text:
AFTER: pushl %ebp
AFTER: movl %esp, %ebp
AFTER: subl $20, %esp
AFTER: movl $0, -4(%ebp)
AFTER: movl $0, 12(%esp)
AFTER: movl $4198407, 8(%esp)
AFTER: movl $4198400, 4(%esp)
AFTER: movl $0, (%esp)
AFTER: calll *4194304
AFTER: subl $16, %esp
AFTER: xorl %eax, %eax
AFTER: addl $20, %esp
AFTER: popl %ebp
AFTER: ret
CHECK: .text:
CHECK: 2000: 68 02 00 00 00
CHECK: 2005: 68 05 00 00 00
CHECK: 200a: 68 00 10 40 00
CHECK: 200f: 68 00 10 40 00
CHECK: 2014: 68 00 00 40 00