Skip to content

swift-reflection-dump: ELF ObjectMemoryReader support for relocations #27532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/IRGen/IRGenMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,11 @@ IRGenMangler::withSymbolicReferences(IRGenModule &IGM,
}
}

// TODO: ObjectMemoryReader for ELF and PE platforms still does not
// TODO: ObjectMemoryReader for PE platforms still does not
// implement symbol relocations. For now, on non-Mach-O platforms,
// only symbolic reference things in the same module.
if (IGM.TargetInfo.OutputObjectFormat != llvm::Triple::MachO) {
if (IGM.TargetInfo.OutputObjectFormat != llvm::Triple::MachO
&& IGM.TargetInfo.OutputObjectFormat != llvm::Triple::ELF) {
auto formalAccessScope = type->getFormalAccessScope(nullptr, true);
if ((formalAccessScope.isPublic() || formalAccessScope.isInternal()) &&
(!IGM.CurSourceFile ||
Expand Down
4 changes: 4 additions & 0 deletions test/Reflection/typeref_lowering.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// REQUIRES: no_asan
// RUN: %empty-directory(%t)

// RUN: %target-build-swift -Xfrontend -disable-availability-checking %S/Inputs/TypeLowering.swift -parse-as-library -emit-module -emit-library -module-name TypeLowering -o %t/%target-library-name(TypesToReflect)
// RUN: %target-build-swift -Xfrontend -disable-availability-checking %S/Inputs/TypeLowering.swift %S/Inputs/main.swift -emit-module -emit-executable -module-name TypeLowering -o %t/TypesToReflect

// RUN: %target-swift-reflection-dump -binary-filename %t/%target-library-name(TypesToReflect) -binary-filename %platform-module-dir/%target-library-name(swiftCore) -dump-type-lowering < %s | %FileCheck %s --check-prefix=CHECK-%target-ptrsize
// RUN: %target-swift-reflection-dump -binary-filename %t/TypesToReflect -binary-filename %platform-module-dir/%target-library-name(swiftCore) -dump-type-lowering < %s | %FileCheck %s --check-prefix=CHECK-%target-ptrsize

12TypeLowering11BasicStructV
// CHECK-64: (struct TypeLowering.BasicStruct)
Expand Down
74 changes: 70 additions & 4 deletions tools/swift-reflection-dump/swift-reflection-dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/RelocationResolver.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"

Expand Down Expand Up @@ -96,7 +97,11 @@ class Image {
const ObjectFile *O;
uint64_t HeaderAddress;
std::vector<Segment> Segments;
llvm::DenseMap<uint64_t, StringRef> DynamicRelocations;
struct DynamicRelocation {
StringRef Symbol;
uint64_t Offset;
};
llvm::DenseMap<uint64_t, DynamicRelocation> DynamicRelocations;

void scanMachO(const MachOObjectFile *O) {
using namespace llvm::MachO;
Expand Down Expand Up @@ -144,7 +149,25 @@ class Image {
llvm::consumeError(std::move(error));
break;
}
DynamicRelocations.insert({bind.address(), bind.symbolName()});

// The offset from the symbol is stored at the target address.
uint64_t Offset;
auto OffsetContent = getContentsAtAddress(bind.address(),
O->getBytesInAddress());
if (OffsetContent.empty())
continue;

if (O->getBytesInAddress() == 8) {
memcpy(&Offset, OffsetContent.data(), sizeof(Offset));
} else if (O->getBytesInAddress() == 4) {
uint32_t OffsetValue;
memcpy(&OffsetValue, OffsetContent.data(), sizeof(OffsetValue));
Offset = OffsetValue;
} else {
assert(false && "unexpected word size?!");
}

DynamicRelocations.insert({bind.address(), {bind.symbolName(), Offset}});
}
if (error) {
llvm::consumeError(std::move(error));
Expand All @@ -160,7 +183,6 @@ class Image {
auto phdrs = O->getELFFile()->program_headers();
if (!phdrs) {
llvm::consumeError(phdrs.takeError());
return;
}

for (auto &ph : *phdrs) {
Expand All @@ -175,6 +197,45 @@ class Image {
Segments.push_back({ph.p_vaddr, contents});
HeaderAddress = std::min(HeaderAddress, (uint64_t)ph.p_vaddr);
}

// Collect the dynamic relocations.
auto resolver = getRelocationResolver(*O);
auto resolverSupports = resolver.first;
auto resolve = resolver.second;

if (!resolverSupports || !resolve)
return;

auto machine = O->getELFFile()->getHeader()->e_machine;
auto relativeRelocType = getELFRelativeRelocationType(machine);

for (auto &S : static_cast<const ELFObjectFileBase*>(O)
->dynamic_relocation_sections()) {
bool isRela = O->getSection(S.getRawDataRefImpl())->sh_type
== llvm::ELF::SHT_RELA;

for (const RelocationRef &R : S.relocations()) {
// `getRelocationResolver` doesn't handle RELATIVE relocations, so we
// have to do that ourselves.
if (isRela && R.getType() == relativeRelocType) {
auto rela = O->getRela(R.getRawDataRefImpl());
DynamicRelocations.insert({R.getOffset(),
{{}, HeaderAddress + rela->r_addend}});
continue;
}

if (!resolverSupports(R.getType()))
continue;
auto symbol = R.getSymbol();
auto name = symbol->getName();
if (!name) {
llvm::consumeError(name.takeError());
continue;
}
uint64_t offset = resolve(R, 0, 0);
DynamicRelocations.insert({R.getOffset(), {*name, offset}});
}
}
}

void scanELF(const ELFObjectFileBase *O) {
Expand All @@ -186,6 +247,8 @@ class Image {
scanELFType(le64);
} else if (auto be64 = dyn_cast<ELFObjectFile<ELF64BE>>(O)) {
scanELFType(be64);
} else {
return;
}

// FIXME: ReflectionContext tries to read bits of the ELF structure that
Expand Down Expand Up @@ -215,6 +278,8 @@ class Image {
Segments.push_back({SectionBase, SectionContent});
}

// FIXME: We need to map the header at least, but how much of it does
// Windows typically map?
Segments.push_back({HeaderAddress, O->getData()});
}

Expand Down Expand Up @@ -272,7 +337,8 @@ class Image {
if (found == DynamicRelocations.end())
result = RemoteAbsolutePointer("", pointerValue);
else
result = RemoteAbsolutePointer(found->second, pointerValue);
result = RemoteAbsolutePointer(found->second.Symbol,
found->second.Offset);
return result;
}
};
Expand Down