Skip to content

Commit

Permalink
[llvm-readobj][COFF] Dump hybrid object for ARM64X files.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjacek committed Aug 6, 2024
1 parent 278c0ad commit e01449a
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 7 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/Object/COFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,7 @@ class COFFObjectFile : public ObjectFile {
Expected<SubtargetFeatures> getFeatures() const override {
return SubtargetFeatures();
}
std::unique_ptr<MemoryBuffer> getHybridObjectView() const;

import_directory_iterator import_directory_begin() const;
import_directory_iterator import_directory_end() const;
Expand Down
48 changes: 48 additions & 0 deletions llvm/lib/Object/COFFObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,54 @@ StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
.Default(Name);
}

std::unique_ptr<MemoryBuffer> COFFObjectFile::getHybridObjectView() const {
if (getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64X)
return nullptr;

std::unique_ptr<WritableMemoryBuffer> HybridView;

for (auto DynReloc : dynamic_relocs()) {
if (DynReloc.getType() != COFF::IMAGE_DYNAMIC_RELOCATION_ARM64X)
continue;

for (auto reloc : DynReloc.arm64x_relocs()) {
if (!HybridView) {
HybridView =
WritableMemoryBuffer::getNewUninitMemBuffer(Data.getBufferSize());
memcpy(HybridView->getBufferStart(), Data.getBufferStart(),
Data.getBufferSize());
}

uint32_t RVA = reloc.getRVA();
void *Ptr;
uintptr_t IntPtr;
if (RVA & ~0xfff) {
cantFail(getRvaPtr(RVA, IntPtr));
Ptr = HybridView->getBufferStart() + IntPtr -
reinterpret_cast<uintptr_t>(base());
} else {
// PE header relocation.
Ptr = HybridView->getBufferStart() + RVA;
}

switch (reloc.getType()) {
case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:
memset(Ptr, 0, reloc.getSize());
break;
case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: {
auto Value = static_cast<ulittle64_t>(reloc.getValue());
memcpy(Ptr, &Value, reloc.getSize());
break;
}
case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:
*reinterpret_cast<ulittle32_t *>(Ptr) += reloc.getValue();
break;
}
}
}
return HybridView;
}

bool ImportDirectoryEntryRef::
operator==(const ImportDirectoryEntryRef &Other) const {
return ImportTable == Other.ImportTable && Index == Other.Index;
Expand Down
144 changes: 144 additions & 0 deletions llvm/test/tools/llvm-readobj/COFF/arm64x-reloc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,32 @@
# CHECK-NEXT: ]
# CHECK-NEXT: ]

# RUN: llvm-readobj --hex-dump=.test %t.dll | FileCheck --check-prefix=HEX %s
# HEX: Format: COFF-ARM64X
# HEX-NEXT: Arch: aarch64
# HEX-NEXT: AddressSize: 64bit
# HEX-EMPTY:
# HEX-NEXT: Hex dump of section '.test':
# HEX-NEXT: 0x180006000 11112222 33334444 55556666 77778888 ..""33DDUUffww..
# HEX-NEXT: 0x180006010 9999aaaa bbbbcccc ddddeeee ffff0000 ................
# HEX-NEXT: 0x180006020 00000000 00000000 00000000 00000000 ................
# HEX-NEXT: 0x180006030 00000000 00000000 00000000 00000000 ................
# HEX-NEXT: 0x180006040 10101010 20202020 30303030 40404040 .... 0000@@@@
# HEX-NEXT: 0x180006050 50505050 60606060 70707070 80808080 PPPP````pppp....
# HEX-NEXT: HybridObject {
# HEX-NEXT: Format: COFF-ARM64EC
# HEX-NEXT: Arch: aarch64
# HEX-NEXT: AddressSize: 64bit
# HEX-EMPTY:
# HEX-NEXT: Hex dump of section '.test':
# HEX-NEXT: 0x180006000 00002222 00000000 55556666 77778888 ..""....UUffww..
# HEX-NEXT: 0x180006010 00000000 00000000 ddddeeee ffff0000 ................
# HEX-NEXT: 0x180006020 12340000 23456789 11223344 55667788 .4..#Eg.."3DUfw.
# HEX-NEXT: 0x180006030 00000000 00000000 00000000 00000000 ................
# HEX-NEXT: 0x180006040 941c1110 28392220 20303030 20404040 ....(9" 000 @@@
# HEX-NEXT: 0x180006050 50505050 60606060 70707070 80808080 PPPP````pppp....
# HEX-NEXT: }


--- !COFF
OptionalHeader:
Expand Down Expand Up @@ -203,6 +229,7 @@ symbols: []

# RUN: yaml2obj %s --docnum=2 -o %t2.dll
# RUN: llvm-readobj --coff-load-config %t2.dll | FileCheck --check-prefixes=CHECK,V2 %s
# RUN: llvm-readobj --hex-dump=.test %t2.dll | FileCheck --check-prefix=HEX %s

--- !COFF
OptionalHeader:
Expand Down Expand Up @@ -320,3 +347,120 @@ sections:
- Binary: 0000 # terminator
symbols: []
...

# RUN: yaml2obj %s --docnum=3 -o %t3.dll
# RUN: llvm-readobj --coff-exports %t3.dll | FileCheck --check-prefix=EXP %s

# EXP: Format: COFF-ARM64X
# EXP-NEXT: Arch: aarch64
# EXP-NEXT: AddressSize: 64bit
# EXP-NEXT: Export {
# EXP-NEXT: Ordinal: 1
# EXP-NEXT: Name: test
# EXP-NEXT: RVA: 0x2000
# EXP-NEXT: }
# EXP-NEXT: HybridObject {
# EXP-NEXT: Format: COFF-ARM64EC
# EXP-NEXT: Arch: aarch64
# EXP-NEXT: AddressSize: 64bit
# EXP-NEXT: Export {
# EXP-NEXT: Ordinal: 1
# EXP-NEXT: Name: test
# EXP-NEXT: RVA: 0x2004
# EXP-NEXT: }
# EXP-NEXT: }

--- !COFF
OptionalHeader:
ImageBase: 0x180000000
SectionAlignment: 4096
FileAlignment: 512
DLLCharacteristics: [ ]
AddressOfEntryPoint: 0
ExportTable:
RelativeVirtualAddress: 0x1000
Size: 64
LoadConfigTable:
RelativeVirtualAddress: 0x3000
Size: 320
header:
Machine: IMAGE_FILE_MACHINE_ARM64
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ]
sections:
- Name: .rdata
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
VirtualAddress: 0x1000
VirtualSize: 64
StructuredData:
- UInt32: 0 # ExportFlags
- UInt32: 0 # TimeDateStamp
- UInt32: 0 # Version
- UInt32: 0x1028 # NameRVA
- UInt32: 1 # OrdinalBase
- UInt32: 1 # AddressTableEntries
- UInt32: 1 # NumberOfNamePointers
- UInt32: 0x1030 # ExportAddressTableRVA
- UInt32: 0x1034 # NamePointerRVA
- UInt32: 0x1038 # OrdinalTableRVA
- Binary: 7473742E646C6C00 # "tst.dll"
- UInt32: 0x2000 # export RVA
- UInt32: 0x103A # name RVA
- Binary: 0000 # ordinal
- Binary: 7465737400 # "test"
- Name: .data
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
VirtualAddress: 0x2000
VirtualSize: 80
StructuredData:
- UInt32: 1 # Version
- UInt32: 0 # CodeMap
- UInt32: 0 # CodeMapCount
- UInt32: 0 # CodeRangesToEntryPoints
- UInt32: 0 # RedirectionMetadata
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0 # CodeRangesToEntryPointsCount
- UInt32: 0 # RedirectionMetadataCount
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- UInt32: 0
- Name: .cfg
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
VirtualAddress: 0x3000
VirtualSize: 328
StructuredData:
- LoadConfig:
CHPEMetadataPointer: 0x180002000
DynamicValueRelocTableOffset: 0
DynamicValueRelocTableSection: 4
- Name: .arm64x
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_DISCARDABLE ]
VirtualAddress: 0x4000
VirtualSize: 56
StructuredData:
- UInt32: 2 # coff_dynamic_reloc_table.Version
- UInt32: 48 # coff_dynamic_reloc_table.Size
- UInt32: 24 # coff_dynamic_relocation64_v2.HeaderSize
- UInt32: 24 # coff_dynamic_relocation64_v2.FixupInfoSize
- UInt32: 6 # coff_dynamic_relocation64_v2.Symbol(low) = IMAGE_DYNAMIC_RELOCATION_ARM64X
- UInt32: 0 # coff_dynamic_relocation64_v2.Symbol(high)
- UInt32: 0 # coff_dynamic_relocation64_v2.SymbolGroup
- UInt32: 0 # coff_dynamic_relocation64_v2.Flags
- UInt32: 0 # coff_base_reloc_block_header[0].PageRVA
- UInt32: 12 # coff_base_reloc_block_header[0].BlockSize
- Binary: 8450 # VALUE offset 0x84 (PE header Machine), size 2
- Binary: 6486 # IMAGE_FILE_MACHINE_AMD64
- UInt32: 0x1000 # coff_base_reloc_block_header[1].PageRVA
- UInt32: 12 # coff_base_reloc_block_header[1].BlockSize
- Binary: 3020 # DELTA offset 0x30, mul 4
- Binary: 0100
symbols: []
...
13 changes: 13 additions & 0 deletions llvm/tools/llvm-readobj/COFFDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class COFFDumper : public ObjDumper {
void printCOFFTLSDirectory() override;
void printCOFFResources() override;
void printCOFFLoadConfig() override;
void printCOFFHybridObject() override;
void printCodeViewDebugInfo() override;
void mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
llvm::codeview::MergingTypeTableBuilder &CVTypes,
Expand Down Expand Up @@ -2271,3 +2272,15 @@ void COFFDumper::printCOFFTLSDirectory(
ArrayRef(ImageSectionCharacteristics),
COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
}

void COFFDumper::printCOFFHybridObject() {
std::unique_ptr<MemoryBuffer> HybridView = Obj->getHybridObjectView();
if (!HybridView)
return;
Expected<std::unique_ptr<COFFObjectFile>> HybridObjOrErr =
COFFObjectFile::create(*HybridView);
if (!HybridObjOrErr)
reportError(HybridObjOrErr.takeError(), Obj->getFileName().str());
DictScope D(Writer, "HybridObject");
ObjDumper::dumpObject(**HybridObjOrErr, Writer, nullptr, true);
}
6 changes: 4 additions & 2 deletions llvm/tools/llvm-readobj/ObjDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ void ObjDumper::printAsStringList(StringRef StringContent,
void ObjDumper::printFileSummary(StringRef FileStr, object::ObjectFile &Obj,
ArrayRef<std::string> InputFilenames,
const object::Archive *A) {
W.getOStream() << "\n";
W.printString("File", FileStr);
if (!FileStr.empty()) {
W.getOStream() << "\n";
W.printString("File", FileStr);
}
W.printString("Format", Obj.getFileFormatName());
W.printString("Arch", Triple::getArchTypeName(Obj.getArch()));
W.printString("AddressSize",
Expand Down
5 changes: 5 additions & 0 deletions llvm/tools/llvm-readobj/ObjDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class ObjDumper {
virtual void printCOFFTLSDirectory() {}
virtual void printCOFFResources() {}
virtual void printCOFFLoadConfig() { }
virtual void printCOFFHybridObject() {}
virtual void printCodeViewDebugInfo() { }
virtual void
mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
Expand Down Expand Up @@ -185,6 +186,10 @@ class ObjDumper {
void reportUniqueWarning(Error Err) const;
void reportUniqueWarning(const Twine &Msg) const;

static void dumpObject(object::ObjectFile &Obj, ScopedPrinter &Writer,
const object::Archive *A = nullptr,
bool IsHybrid = false);

protected:
ScopedPrinter &W;

Expand Down
13 changes: 8 additions & 5 deletions llvm/tools/llvm-readobj/llvm-readobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) {
}

/// Dumps the specified object file.
static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
const Archive *A = nullptr) {
void ObjDumper::dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
const Archive *A, bool IsHybrid) {
std::string FileStr =
A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str()
: Obj.getFileName().str();
Expand Down Expand Up @@ -538,6 +538,9 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
Dumper->printStackMap();
if (opts::PrintStackSizes)
Dumper->printStackSizes();

if (!IsHybrid && Obj.isCOFF())
Dumper->printCOFFHybridObject();
}

/// Dumps each object file in \a Arc;
Expand All @@ -553,7 +556,7 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {

Binary *Bin = ChildOrErr->get();
if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin))
dumpObject(*Obj, Writer, Arc);
ObjDumper::dumpObject(*Obj, Writer, Arc);
else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin))
dumpCOFFImportFile(Imp, Writer);
else
Expand All @@ -572,7 +575,7 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
if (ObjOrErr)
dumpObject(*ObjOrErr.get(), Writer);
ObjDumper::dumpObject(*ObjOrErr.get(), Writer);
else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
reportError(ObjOrErr.takeError(), UBinary->getFileName());
else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
Expand Down Expand Up @@ -618,7 +621,7 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) {
dyn_cast<MachOUniversalBinary>(Bin.get()))
dumpMachOUniversalBinary(UBinary, Writer);
else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin.get()))
dumpObject(*Obj, Writer);
ObjDumper::dumpObject(*Obj, Writer);
else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(Bin.get()))
dumpCOFFImportFile(Import, Writer);
else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(Bin.get()))
Expand Down

0 comments on commit e01449a

Please sign in to comment.