Index: include/llvm/Object/COFF.h =================================================================== --- include/llvm/Object/COFF.h +++ include/llvm/Object/COFF.h @@ -928,6 +928,7 @@ uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; + Expected getStartAddress() const override; SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } import_directory_iterator import_directory_begin() const; Index: include/llvm/Object/ELFObjectFile.h =================================================================== --- include/llvm/Object/ELFObjectFile.h +++ include/llvm/Object/ELFObjectFile.h @@ -373,6 +373,7 @@ uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; + Expected getStartAddress() const override; unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; } @@ -1143,6 +1144,11 @@ } } +template +Expected ELFObjectFile::getStartAddress() const { + return EF.getHeader()->e_entry; +} + template ELFObjectFileBase::elf_symbol_iterator_range ELFObjectFile::getDynamicSymbolIterators() const { Index: include/llvm/Object/ObjectFile.h =================================================================== --- include/llvm/Object/ObjectFile.h +++ include/llvm/Object/ObjectFile.h @@ -287,6 +287,9 @@ virtual Triple::ArchType getArch() const = 0; virtual SubtargetFeatures getFeatures() const = 0; virtual void setARMSubArch(Triple &TheTriple) const { } + virtual Expected getStartAddress() const { + return errorCodeToError(object_error::parse_failed); + }; /// Create a triple from the data in this object file. Triple makeTriple() const; Index: lib/Object/COFFObjectFile.cpp =================================================================== --- lib/Object/COFFObjectFile.cpp +++ lib/Object/COFFObjectFile.cpp @@ -910,6 +910,12 @@ } } +Expected COFFObjectFile::getStartAddress() const { + if (PE32Header) + return PE32Header->AddressOfEntryPoint; + return 0; +} + iterator_range COFFObjectFile::import_directories() const { return make_range(import_directory_begin(), import_directory_end()); Index: test/tools/llvm-objdump/file-headers-coff.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/file-headers-coff.test @@ -0,0 +1,13 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objdump -f %t | FileCheck %s +# RUN: llvm-objdump -file-headers %t | FileCheck %s + +!COFF +header: !Header + Machine: IMAGE_FILE_MACHINE_I386 # (0x14c) + Characteristics: [ IMAGE_FILE_DEBUG_STRIPPED ] +sections: +symbols: + +# CHECK: architecture: i386 +# CHECK: start address: 0x0000 Index: test/tools/llvm-objdump/file-headers-elf.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/file-headers-elf.test @@ -0,0 +1,14 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objdump -f %t | FileCheck %s +# RUN: llvm-objdump -file-headers %t | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + Entry: 0x123456 + +# CHECK: architecture: x86_64 +# CHECK: start address: 0x00123456 Index: test/tools/llvm-objdump/file-headers-pe.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/file-headers-pe.test @@ -0,0 +1,33 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objdump -f %t | FileCheck %s +# RUN: llvm-objdump -file-headers %t | FileCheck %s + +!COFF +header: !Header + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ IMAGE_FILE_DEBUG_STRIPPED ] +OptionalHeader: + AddressOfEntryPoint: 0x1234 +# Unfortunately, all these flags are mandatory to set AddressOfEntryPoint. +# All the values are randomly picked. They can't interfere in what +# we are testing here. + SizeOfHeapCommit: 1024 + SizeOfHeapReserve: 1024 + SizeOfStackCommit: 1024 + SizeOfStackReserve: 1024 + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ] + Subsystem: IMAGE_SUBSYSTEM_NATIVE + MinorSubsystemVersion: 1 + MajorSubsystemVersion: 1 + MinorImageVersion: 1 + MajorImageVersion: 1 + MinorOperatingSystemVersion: 1 + MajorOperatingSystemVersion: 1 + FileAlignment: 8 + SectionAlignment: 8 + ImageBase: 0x12 +sections: +symbols: + +# CHECK: architecture: i386 +# CHECK: start address: 0x1234 Index: test/tools/llvm-objdump/file-headers-unsupported.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/file-headers-unsupported.test @@ -0,0 +1,3 @@ +# RUN: not llvm-objdump -file-headers %p/Inputs/trivial.obj.wasm 2>&1 | FileCheck %s + +# CHECK: Invalid/Unsupported object file format Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -38,6 +38,7 @@ extern cl::opt NoShowRawInsn; extern cl::opt NoLeadingAddr; extern cl::opt PrivateHeaders; +extern cl::opt FileHeaders; extern cl::opt FirstPrivateHeader; extern cl::opt ExportsTrie; extern cl::opt Rebase; Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -200,6 +200,13 @@ PrivateHeadersShort("p", cl::desc("Alias for --private-headers"), cl::aliasopt(PrivateHeaders)); +cl::opt llvm::FileHeaders( + "file-headers", + cl::desc("Display the contents of the overall file header")); + +static cl::alias FileHeadersShort("f", cl::desc("Alias for --file-headers"), + cl::aliasopt(FileHeaders)); + cl::opt llvm::PrintImmHex("print-imm-hex", cl::desc("Use hex format for immediate values")); @@ -2123,6 +2130,20 @@ report_error(o->getFileName(), "Invalid/Unsupported object file format"); } +static void printFileHeaders(const ObjectFile *o) { + if (!o->isELF() && !o->isCOFF()) + report_error(o->getFileName(), "Invalid/Unsupported object file format"); + + Triple::ArchType AT = o->getArch(); + outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n"; + Expected StartAddrOrErr = o->getStartAddress(); + if (!StartAddrOrErr) + report_error(o->getFileName(), StartAddrOrErr.takeError()); + outs() << "start address: " + << format("0x%0*x", o->getBytesInAddress(), StartAddrOrErr.get()) + << "\n"; +} + static void DumpObject(ObjectFile *o, const Archive *a = nullptr) { StringRef ArchiveName = a != nullptr ? a->getFileName() : ""; // Avoid other output when using a raw option. @@ -2151,6 +2172,8 @@ PrintUnwindInfo(o); if (PrivateHeaders || FirstPrivateHeader) printPrivateFileHeaders(o, FirstPrivateHeader); + if (FileHeaders) + printFileHeaders(o); if (ExportsTrie) printExportsTrie(o); if (Rebase) @@ -2267,6 +2290,7 @@ && !SymbolTable && !UnwindInfo && !PrivateHeaders + && !FileHeaders && !FirstPrivateHeader && !ExportsTrie && !Rebase