Index: include/llvm/Object/COFF.h =================================================================== --- include/llvm/Object/COFF.h +++ include/llvm/Object/COFF.h @@ -971,6 +971,9 @@ return nullptr; return reinterpret_cast(base()); } + std::error_code getCOFFHeader(const coff_file_header *&Res) const; + std::error_code + getCOFFBigObjHeader(const coff_bigobj_file_header *&Res) const; std::error_code getPE32Header(const pe32_header *&Res) const; std::error_code getPE32PlusHeader(const pe32plus_header *&Res) const; std::error_code getDataDirectory(uint32_t index, Index: lib/Object/COFFObjectFile.cpp =================================================================== --- lib/Object/COFFObjectFile.cpp +++ lib/Object/COFFObjectFile.cpp @@ -938,6 +938,18 @@ return make_range(base_reloc_begin(), base_reloc_end()); } +std::error_code +COFFObjectFile::getCOFFHeader(const coff_file_header *&Res) const { + Res = COFFHeader; + return std::error_code(); +} + +std::error_code +COFFObjectFile::getCOFFBigObjHeader(const coff_bigobj_file_header *&Res) const { + Res = COFFBigObjHeader; + return std::error_code(); +} + std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { Res = PE32Header; return std::error_code(); Index: test/tools/llvm-objcopy/COFF/Inputs/i386-exe.yaml =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/Inputs/i386-exe.yaml @@ -0,0 +1,84 @@ +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4144 + ImageBase: 4194304 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 6 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_NO_SEH, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 0 + Size: 0 + ImportTable: + RelativeVirtualAddress: 0 + Size: 0 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 0 + Size: 0 + CertificateTable: + RelativeVirtualAddress: 0 + Size: 0 + BaseRelocationTable: + RelativeVirtualAddress: 12288 + Size: 12 + Debug: + RelativeVirtualAddress: 0 + Size: 0 + Architecture: + RelativeVirtualAddress: 0 + Size: 0 + GlobalPtr: + RelativeVirtualAddress: 0 + Size: 0 + TlsTable: + RelativeVirtualAddress: 0 + Size: 0 + LoadConfigTable: + RelativeVirtualAddress: 0 + Size: 0 + BoundImport: + RelativeVirtualAddress: 0 + Size: 0 + IAT: + RelativeVirtualAddress: 0 + Size: 0 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 83 + SectionData: 5589E5508B45088B0D00204000034D088945FC89C883C4045DC3660F1F4400005589E55DC3662E0F1F840000000000905589E583EC08E8E5FFFFFFC745FC00000000C7042402000000E8B2FFFFFF83C4085DC3 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 8192 + VirtualSize: 4 + SectionData: '01000000' + - Name: .reloc + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 12 + SectionData: 001000000C00000009300000 +symbols: [] +... Index: test/tools/llvm-objcopy/COFF/Inputs/i386-obj.yaml =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/Inputs/i386-obj.yaml @@ -0,0 +1,244 @@ +--- !COFF +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: 5589E5508B45088B0D00000000034D088945FC89C883C4045DC3660F1F4400005589E55DC3662E0F1F840000000000905589E583EC08E800000000C745FC00000000C7042402000000E80000000083C4085DC3 + Relocations: + - VirtualAddress: 9 + SymbolName: _x + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 55 + SymbolName: ___main + Type: IMAGE_REL_I386_REL32 + - VirtualAddress: 74 + SymbolName: _f + Type: IMAGE_REL_I386_REL32 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '01000000' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .debug_str + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 636C616E672076657273696F6E20382E302E3020287472756E6B203334363337382920286C6C766D2F7472756E6B203334363339302900736F757263652E63002F686F6D652F6D617274696E2F636F64652F6C6C766D2F6275696C642F6F626A636F70792D696E707574007800696E740066005F5F6D61696E006D61696E007900 + - Name: .debug_abbrev + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 011101250E1305030E10171B0E110112060000023400030E49133A0B3B0B02180000032400030E3E0B0B0B0000042E01110112064018030E3A0B3B0B271949133F1900000505000218030E3A0B3B0B49130000062E00110112064018030E3A0B3B0B27193F190000072E00110112064018030E3A0B3B0B49133F19000000 + - Name: .debug_info + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 850000000400000000000401000000000C003700000000000000400000000000000053000000026B000000370000000101050300000000036D000000050404000000001A000000015571000000010337000000050291087F00000001033700000000062000000005000000015573000000010707300000002300000001557A00000001093700000000 + Relocations: + - VirtualAddress: 6 + SymbolName: .debug_abbrev + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 12 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 18 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 22 + SymbolName: .debug_line + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 26 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 30 + SymbolName: .text + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 39 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 51 + SymbolName: _x + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 56 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 63 + SymbolName: .text + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 73 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 87 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 99 + SymbolName: .text + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 109 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 116 + SymbolName: .text + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 126 + SymbolName: .debug_str + Type: IMAGE_REL_I386_SECREL + - Name: .debug_macinfo + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: '00' + - Name: .debug_line + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 52000000040020000000010101FB0E0D00010101010000000100000100736F757263652E6300000000000005020000000014050A0A75050C0666050366050006CB05010A3D0500C9050A0A0821050306BA0205000101 + Relocations: + - VirtualAddress: 45 + SymbolName: .text + Type: IMAGE_REL_I386_DIR32 + - Name: .llvm_addrsig + Characteristics: [ IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: '1314' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 83 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 4183332250 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3099354981 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .debug_str + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 129 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2876129505 + Number: 4 + - Name: .debug_abbrev + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 126 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2218663305 + Number: 5 + - Name: .debug_info + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 137 + NumberOfRelocations: 16 + NumberOfLinenumbers: 0 + CheckSum: 2577207131 + Number: 6 + - Name: .debug_macinfo + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 7 + - Name: .debug_line + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 86 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 2357396799 + Number: 8 + - Name: .llvm_addrsig + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 2 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2067109359 + Number: 9 + - Name: '@feat.00' + Value: 1 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: _f + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _x + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: ___main + Value: 32 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _main + Value: 48 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: test/tools/llvm-objcopy/COFF/Inputs/x86_64-exe.yaml =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/Inputs/x86_64-exe.yaml @@ -0,0 +1,89 @@ +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4144 + ImageBase: 1073741824 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 6 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 0 + Size: 0 + ImportTable: + RelativeVirtualAddress: 0 + Size: 0 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 16384 + Size: 24 + CertificateTable: + RelativeVirtualAddress: 0 + Size: 0 + BaseRelocationTable: + RelativeVirtualAddress: 0 + Size: 0 + Debug: + RelativeVirtualAddress: 0 + Size: 0 + Architecture: + RelativeVirtualAddress: 0 + Size: 0 + GlobalPtr: + RelativeVirtualAddress: 0 + Size: 0 + TlsTable: + RelativeVirtualAddress: 0 + Size: 0 + LoadConfigTable: + RelativeVirtualAddress: 0 + Size: 0 + BoundImport: + RelativeVirtualAddress: 0 + Size: 0 + IAT: + RelativeVirtualAddress: 0 + Size: 0 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 87 + SectionData: 50894C24048B0DF51F0000034C240489C859C3662E0F1F8400000000000F1F00C3662E0F1F8400000000000F1F440000554883EC30488D6C2430E8E1FFFFFFC745FC00000000B902000000E8B0FFFFFF904883C4305DC3 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 20 + SectionData: 0101010001020000010A03350A03055201500000 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 12288 + VirtualSize: 4 + SectionData: '01000000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 16384 + VirtualSize: 24 + SectionData: '001000001310000000200000301000005710000008200000' +symbols: [] +... Index: test/tools/llvm-objcopy/COFF/Inputs/x86_64-obj.yaml =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/Inputs/x86_64-obj.yaml @@ -0,0 +1,295 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 50894C24048B0D00000000034C240489C859C3662E0F1F8400000000000F1F00C3662E0F1F8400000000000F1F440000554883EC30488D6C2430E800000000C745FC00000000B902000000E800000000904883C4305DC3 + Relocations: + - VirtualAddress: 7 + SymbolName: x + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 59 + SymbolName: __main + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 76 + SymbolName: f + Type: IMAGE_REL_AMD64_REL32 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '01000000' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0101010001020000010A03350A03055201500000 + - Name: .debug_str + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 636C616E672076657273696F6E20382E302E3020287472756E6B203334363337382920286C6C766D2F7472756E6B203334363339302900736F757263652E63002F686F6D652F6D617274696E2F636F64652F6C6C766D2F6275696C642F6F626A636F70792D696E707574007800696E740066005F5F6D61696E006D61696E007900 + - Name: .debug_abbrev + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 011101250E1305030E10171B0E110112060000023400030E49133A0B3B0B02180000032400030E3E0B0B0B0000042E01110112064018030E3A0B3B0B271949133F1900000505000218030E3A0B3B0B49130000062E00110112064018030E3A0B3B0B27193F190000072E00110112064018030E3A0B3B0B49133F19000000 + - Name: .debug_info + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 990000000400000000000801000000000C00370000000000000040000000000000000000000057000000026B0000003F000000010109030000000000000000036D00000005040400000000000000001300000001577100000001033F000000050291047F00000001033F000000000620000000000000000100000001577300000001070730000000000000002700000001567A00000001093F00000000 + Relocations: + - VirtualAddress: 6 + SymbolName: .debug_abbrev + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 12 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 18 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 22 + SymbolName: .debug_line + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 26 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 30 + SymbolName: .text + Type: IMAGE_REL_AMD64_ADDR64 + - VirtualAddress: 43 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 55 + SymbolName: x + Type: IMAGE_REL_AMD64_ADDR64 + - VirtualAddress: 64 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 71 + SymbolName: .text + Type: IMAGE_REL_AMD64_ADDR64 + - VirtualAddress: 85 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 99 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 111 + SymbolName: .text + Type: IMAGE_REL_AMD64_ADDR64 + - VirtualAddress: 125 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 132 + SymbolName: .text + Type: IMAGE_REL_AMD64_ADDR64 + - VirtualAddress: 146 + SymbolName: .debug_str + Type: IMAGE_REL_AMD64_SECREL + - Name: .debug_macinfo + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: '00' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000001300000000000000000000002700000008000000' + Relocations: + - VirtualAddress: 0 + SymbolName: f + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: f + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: .xdata + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 12 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 16 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 20 + SymbolName: .xdata + Type: IMAGE_REL_AMD64_ADDR32NB + - Name: .debug_line + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 57000000040020000000010101FB0E0D00010101010000000100000100736F757263652E630000000000000902000000000000000014050A0A59050C066605034A050006081505010A130500F3050A0A08590503069E0207000101 + Relocations: + - VirtualAddress: 45 + SymbolName: .text + Type: IMAGE_REL_AMD64_ADDR64 + - Name: .llvm_addrsig + Characteristics: [ IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: '1718' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 87 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 4237828689 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3099354981 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .xdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 20 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3415491858 + Number: 4 + - Name: .debug_str + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 129 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2876129505 + Number: 5 + - Name: .debug_abbrev + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 126 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 2218663305 + Number: 6 + - Name: .debug_info + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 157 + NumberOfRelocations: 16 + NumberOfLinenumbers: 0 + CheckSum: 603506744 + Number: 7 + - Name: .debug_macinfo + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 8 + - Name: .pdata + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 24 + NumberOfRelocations: 6 + NumberOfLinenumbers: 0 + CheckSum: 2036901199 + Number: 9 + - Name: .debug_line + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 91 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 633454091 + Number: 10 + - Name: .llvm_addrsig + Value: 0 + SectionNumber: 11 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 2 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 384769216 + Number: 11 + - Name: '@feat.00' + Value: 0 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: f + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: x + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: __main + Value: 32 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 48 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: test/tools/llvm-objcopy/COFF/basic-copy.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/basic-copy.test @@ -0,0 +1,42 @@ +Test plain passthrough copying with llvm-objcopy, by checking that obj2yaml +produces identical output for both input and output object files/executables. +(Intentionally not comparing to the original input yaml, in case there are +superficial differences like line endings.) In order to have a check of the +whole file and not just individual fields with FileCheck, checking with +obj2yaml+cmp instead of llvm-readobj+cmp, as llvm-readobj also prints file +details that can differ between otherwise equal files (such as file offsets). + +Actual copied object files/executables can differ in, among others, the +following aspects: +- The padding of executable sections (lld uses 0xcc, which is int3 on x86) +- The actual layout of the string table (it can be filled linearly, + strings can be dedupliated, the table can be optimized by sharing tails + of longer strings; different parts in llvm do each of these three options) +- The size indication for an empty/missing string table can either be 4 + or left out altogether +- Alignment of section data +- Checksums + +RUN: yaml2obj %p/Inputs/i386-obj.yaml > %t.i386.o +RUN: llvm-objcopy %t.i386.o %t.i386-copy.o +RUN: obj2yaml %t.i386.o > %t.i386.o.yaml +RUN: obj2yaml %t.i386-copy.o > %t.i386-copy.o.yaml +RUN: cmp %t.i386.o.yaml %t.i386-copy.o.yaml + +RUN: yaml2obj %p/Inputs/x86_64-obj.yaml > %t.x86_64.o +RUN: llvm-objcopy %t.x86_64.o %t.x86_64-copy.o +RUN: obj2yaml %t.x86_64.o > %t.x86_64.o.yaml +RUN: obj2yaml %t.x86_64-copy.o > %t.x86_64-copy.o.yaml +RUN: cmp %t.x86_64.o.yaml %t.x86_64-copy.o.yaml + +RUN: yaml2obj %p/Inputs/i386-exe.yaml > %t.i386.exe +RUN: llvm-objcopy %t.i386.exe %t.i386-copy.exe +RUN: obj2yaml %t.i386.exe > %t.i386.exe.yaml +RUN: obj2yaml %t.i386-copy.exe > %t.i386-copy.exe.yaml +RUN: cmp %t.i386.exe.yaml %t.i386-copy.exe.yaml + +RUN: yaml2obj %p/Inputs/x86_64-exe.yaml > %t.x86_64.exe +RUN: llvm-objcopy %t.x86_64.exe %t.x86_64-copy.exe +RUN: obj2yaml %t.x86_64.exe > %t.x86_64.exe.yaml +RUN: obj2yaml %t.x86_64-copy.exe > %t.x86_64-copy.exe.yaml +RUN: cmp %t.x86_64.exe.yaml %t.x86_64-copy.exe.yaml Index: tools/llvm-objcopy/CMakeLists.txt =================================================================== --- tools/llvm-objcopy/CMakeLists.txt +++ tools/llvm-objcopy/CMakeLists.txt @@ -17,6 +17,9 @@ Buffer.cpp CopyConfig.cpp llvm-objcopy.cpp + COFF/COFFObjcopy.cpp + COFF/Reader.cpp + COFF/Writer.cpp ELF/ELFObjcopy.cpp ELF/Object.cpp DEPENDS Index: tools/llvm-objcopy/COFF/COFFObjcopy.h =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/COFFObjcopy.h @@ -0,0 +1,31 @@ +//===- COFFObjcopy.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H +#define LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H + +namespace llvm { + +namespace object { +class COFFObjectFile; +} // end namespace object + +namespace objcopy { +struct CopyConfig; +class Buffer; + +namespace coff { +void executeObjcopyOnBinary(const CopyConfig &Config, + object::COFFObjectFile &In, Buffer &Out); + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H Index: tools/llvm-objcopy/COFF/COFFObjcopy.cpp =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -0,0 +1,40 @@ +//===- COFFObjcopy.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "COFFObjcopy.h" +#include "Buffer.h" +#include "CopyConfig.h" +#include "Object.h" +#include "Reader.h" +#include "Writer.h" +#include "llvm-objcopy.h" + +#include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +using namespace object; +using namespace COFF; + +void executeObjcopyOnBinary(const CopyConfig &Config, + object::COFFObjectFile &In, Buffer &Out) { + COFFReader Reader(In); + std::unique_ptr Obj = Reader.create(); + assert(Obj && "Unable to deserialize COFF object"); + COFFWriter Writer(*Obj, Out); + Writer.write(); +} + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm Index: tools/llvm-objcopy/COFF/Object.h =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Object.h @@ -0,0 +1,110 @@ +//===- Object.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H +#define LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" +#include +#include +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +struct Section { + object::coff_section Header; + ArrayRef Contents; + std::vector Relocs; + StringRef Name; +}; + +struct Symbol { + object::coff_symbol32 Sym; + StringRef Name; + ArrayRef AuxData; +}; + +struct Object { + bool IsPE = false; + + object::dos_header DosHeader; + ArrayRef DosStub; + + object::coff_file_header CoffFileHeader; + + bool Is64 = false; + object::pe32plus_header PeHeader; + uint32_t BaseOfData = 0; // pe32plus_header lacks this field. + + std::vector DataDirectories; + std::vector
Sections; + std::vector Symbols; +}; + +// Copy between coff_symbol16 and coff_symbol32. +// The source and destination files can use either coff_symbol16 or +// coff_symbol32, while we always store them as coff_symbol32 in the +// intermediate data structure. +template +void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src) { + static_assert(sizeof(Dest.Name.ShortName) == sizeof(Src.Name.ShortName), + "Mismatched name sizes"); + memcpy(Dest.Name.ShortName, Src.Name.ShortName, sizeof(Dest.Name.ShortName)); + Dest.Value = Src.Value; + Dest.SectionNumber = Src.SectionNumber; + Dest.Type = Src.Type; + Dest.StorageClass = Src.StorageClass; + Dest.NumberOfAuxSymbols = Src.NumberOfAuxSymbols; +} + +// Copy between pe32_header and pe32plus_header. +// We store the intermediate state in a pe32plus_header. +template +void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src) { + Dest.Magic = Src.Magic; + Dest.MajorLinkerVersion = Src.MajorLinkerVersion; + Dest.MinorLinkerVersion = Src.MinorLinkerVersion; + Dest.SizeOfCode = Src.SizeOfCode; + Dest.SizeOfInitializedData = Src.SizeOfInitializedData; + Dest.SizeOfUninitializedData = Src.SizeOfUninitializedData; + Dest.AddressOfEntryPoint = Src.AddressOfEntryPoint; + Dest.BaseOfCode = Src.BaseOfCode; + Dest.ImageBase = Src.ImageBase; + Dest.SectionAlignment = Src.SectionAlignment; + Dest.FileAlignment = Src.FileAlignment; + Dest.MajorOperatingSystemVersion = Src.MajorOperatingSystemVersion; + Dest.MinorOperatingSystemVersion = Src.MinorOperatingSystemVersion; + Dest.MajorImageVersion = Src.MajorImageVersion; + Dest.MinorImageVersion = Src.MinorImageVersion; + Dest.MajorSubsystemVersion = Src.MajorSubsystemVersion; + Dest.MinorSubsystemVersion = Src.MinorSubsystemVersion; + Dest.Win32VersionValue = Src.Win32VersionValue; + Dest.SizeOfImage = Src.SizeOfImage; + Dest.SizeOfHeaders = Src.SizeOfHeaders; + Dest.CheckSum = Src.CheckSum; + Dest.Subsystem = Src.Subsystem; + Dest.DLLCharacteristics = Src.DLLCharacteristics; + Dest.SizeOfStackReserve = Src.SizeOfStackReserve; + Dest.SizeOfStackCommit = Src.SizeOfStackCommit; + Dest.SizeOfHeapReserve = Src.SizeOfHeapReserve; + Dest.SizeOfHeapCommit = Src.SizeOfHeapCommit; + Dest.LoaderFlags = Src.LoaderFlags; + Dest.NumberOfRvaAndSize = Src.NumberOfRvaAndSize; +} + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H Index: tools/llvm-objcopy/COFF/Reader.h =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Reader.h @@ -0,0 +1,47 @@ +//===- Reader.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_COFF_READER_H +#define LLVM_TOOLS_OBJCOPY_COFF_READER_H + +#include "Buffer.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" + +namespace llvm { +namespace objcopy { +namespace coff { + +class Object; + +using object::COFFObjectFile; + +class Reader { +public: + virtual ~Reader(); + virtual std::unique_ptr create() const = 0; +}; + +class COFFReader : public Reader { + const COFFObjectFile &COFFObj; + + void readExecutableHeaders(Object &Obj) const; + void readSections(Object &Obj) const; + void readSymbols(Object &Obj, bool IsBigObj) const; + +public: + explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {} + std::unique_ptr create() const override; +}; + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_COFF_READER_H Index: tools/llvm-objcopy/COFF/Reader.cpp =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Reader.cpp @@ -0,0 +1,141 @@ +//===- Reader.cpp ---------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Reader.h" +#include "Object.h" +#include "llvm-objcopy.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +using namespace object; + +Reader::~Reader() {} + +void COFFReader::readExecutableHeaders(Object &Obj) const { + const dos_header *DH = COFFObj.getDOSHeader(); + Obj.Is64 = COFFObj.is64(); + if (!DH) + return; + + Obj.IsPE = true; + Obj.DosHeader = *DH; + if (DH->AddressOfNewExeHeader > sizeof(*DH)) + Obj.DosStub = ArrayRef(reinterpret_cast(&DH[1]), + DH->AddressOfNewExeHeader - sizeof(*DH)); + + if (COFFObj.is64()) { + const pe32plus_header *PE32Plus = nullptr; + if (auto EC = COFFObj.getPE32PlusHeader(PE32Plus)) + reportError(COFFObj.getFileName(), std::move(EC)); + Obj.PeHeader = *PE32Plus; + } else { + const pe32_header *PE32 = nullptr; + if (auto EC = COFFObj.getPE32Header(PE32)) + reportError(COFFObj.getFileName(), std::move(EC)); + copyPeHeader(Obj.PeHeader, *PE32); + // The pe32plus_header (stored in Object) lacks the BaseOfData field. + Obj.BaseOfData = PE32->BaseOfData; + } + + for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) { + const data_directory *Dir; + if (auto EC = COFFObj.getDataDirectory(I, Dir)) + reportError(COFFObj.getFileName(), std::move(EC)); + Obj.DataDirectories.emplace_back(*Dir); + } +} + +void COFFReader::readSections(Object &Obj) const { + // Section indexing starts from 1. + for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) { + const coff_section *Sec; + if (auto EC = COFFObj.getSection(I, Sec)) + reportError(COFFObj.getFileName(), std::move(EC)); + Obj.Sections.push_back(Section()); + Section &S = Obj.Sections.back(); + S.Header = *Sec; + if (auto EC = COFFObj.getSectionContents(Sec, S.Contents)) + reportError(COFFObj.getFileName(), std::move(EC)); + ArrayRef Relocs = COFFObj.getRelocations(Sec); + S.Relocs.insert(S.Relocs.end(), Relocs.begin(), Relocs.end()); + if (auto EC = COFFObj.getSectionName(Sec, S.Name)) + reportError(COFFObj.getFileName(), std::move(EC)); + if (Sec->hasExtendedRelocations()) + reportError( + COFFObj.getFileName(), + make_error("Extended relocations not supported yet", + object_error::parse_failed)); + } +} + +void COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { + for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) { + Expected SymOrErr = COFFObj.getSymbol(I); + if (!SymOrErr) + reportError(COFFObj.getFileName(), SymOrErr.takeError()); + COFFSymbolRef SymRef = *SymOrErr; + + Obj.Symbols.push_back(Symbol()); + Symbol &Sym = Obj.Symbols.back(); + // Copy symbols from the original form into an intermediate coff_symbol32. + if (IsBigObj) + copySymbol(Sym.Sym, + *reinterpret_cast(SymRef.getRawPtr())); + else + copySymbol(Sym.Sym, + *reinterpret_cast(SymRef.getRawPtr())); + if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name)) + reportError(COFFObj.getFileName(), std::move(EC)); + Sym.AuxData = COFFObj.getSymbolAuxData(SymRef); + assert((Sym.AuxData.size() % + (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0); + I += 1 + SymRef.getNumberOfAuxSymbols(); + } +} + +std::unique_ptr COFFReader::create() const { + auto Obj = llvm::make_unique(); + + const coff_file_header *CFH = nullptr; + const coff_bigobj_file_header *CBFH = nullptr; + COFFObj.getCOFFHeader(CFH); + COFFObj.getCOFFBigObjHeader(CBFH); + bool IsBigObj = false; + if (CFH) { + Obj->CoffFileHeader = *CFH; + } else { + if (!CBFH) + reportError(COFFObj.getFileName(), + make_error("No COFF file header returned", + object_error::parse_failed)); + // Only copying the few fields from the bigobj header that we need + // and won't recreate in the end. + Obj->CoffFileHeader.Machine = CBFH->Machine; + Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp; + IsBigObj = true; + } + + readExecutableHeaders(*Obj); + readSections(*Obj); + readSymbols(*Obj, IsBigObj); + + return Obj; +} + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm Index: tools/llvm-objcopy/COFF/Writer.h =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Writer.h @@ -0,0 +1,69 @@ +//===- Writer.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_COFF_WRITER_H +#define LLVM_TOOLS_OBJCOPY_COFF_WRITER_H + +#include "Buffer.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/FileOutputBuffer.h" +#include +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +class Object; + +class Writer { +protected: + Object &Obj; + Buffer &Buf; + +public: + virtual ~Writer(); + virtual void write() = 0; + + Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {} +}; + +class COFFWriter : public Writer { + size_t FileSize; + size_t FileAlignment; + size_t SizeOfInitializedData; + StringTableBuilder StrTabBuilder; + + void layoutSections(); + size_t finalizeStringTable(); + template std::pair finalizeSymbolTable(); + + void finalize(bool IsBigObj); + + void writeHeaders(bool IsBigObj); + void writeSections(); + template void writeSymbolStringTables(); + + void write(bool IsBigObj); + + void patchDebugDirectory(); + +public: + virtual ~COFFWriter() {} + void write() override; + + COFFWriter(Object &Obj, Buffer &Buf) + : Writer(Obj, Buf), StrTabBuilder(StringTableBuilder::WinCOFF) {} +}; + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_COFF_WRITER_H Index: tools/llvm-objcopy/COFF/Writer.cpp =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Writer.cpp @@ -0,0 +1,319 @@ +//===- Writer.cpp ---------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Writer.h" +#include "Object.h" +#include "llvm-objcopy.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileOutputBuffer.h" +#include +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +using namespace object; +using namespace COFF; + +Writer::~Writer() {} + +void COFFWriter::layoutSections() { + for (auto &S : Obj.Sections) { + if (S.Header.SizeOfRawData > 0) + S.Header.PointerToRawData = FileSize; + FileSize += S.Header.SizeOfRawData; // For executables, this is already + // aligned to FileAlignment. + if (S.Header.NumberOfRelocations > 0) + S.Header.PointerToRelocations = FileSize; + FileSize += S.Relocs.size() * sizeof(coff_relocation); + FileSize = alignTo(FileSize, FileAlignment); + + if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + SizeOfInitializedData += S.Header.SizeOfRawData; + } +} + +size_t COFFWriter::finalizeStringTable() { + for (auto &S : Obj.Sections) + if (S.Name.size() > COFF::NameSize) + StrTabBuilder.add(S.Name); + + for (const auto &S : Obj.Symbols) + if (S.Name.size() > COFF::NameSize) + StrTabBuilder.add(S.Name); + + StrTabBuilder.finalize(); + + for (auto &S : Obj.Sections) { + if (S.Name.size() > COFF::NameSize) { + snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d", + (int)StrTabBuilder.getOffset(S.Name)); + } else { + strncpy(S.Header.Name, S.Name.data(), COFF::NameSize); + } + } + for (auto &S : Obj.Symbols) { + if (S.Name.size() > COFF::NameSize) { + S.Sym.Name.Offset.Zeroes = 0; + S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name); + } else { + strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize); + } + } + return StrTabBuilder.getSize(); +} + +template +std::pair COFFWriter::finalizeSymbolTable() { + size_t SymTabSize = Obj.Symbols.size() * sizeof(SymbolTy); + for (const auto &S : Obj.Symbols) + SymTabSize += S.AuxData.size(); + return std::make_pair(SymTabSize, sizeof(SymbolTy)); +} + +void COFFWriter::finalize(bool IsBigObj) { + size_t SizeOfHeaders = 0; + FileAlignment = 1; + size_t PeHeaderSize = 0; + if (Obj.IsPE) { + Obj.DosHeader.AddressOfNewExeHeader = + sizeof(Obj.DosHeader) + Obj.DosStub.size(); + SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic); + + FileAlignment = Obj.PeHeader.FileAlignment; + Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size(); + + PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header); + SizeOfHeaders += + PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); + } + Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size(); + SizeOfHeaders += + IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header); + SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size(); + SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment); + + Obj.CoffFileHeader.SizeOfOptionalHeader = + PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); + + FileSize = SizeOfHeaders; + SizeOfInitializedData = 0; + + layoutSections(); + + if (Obj.IsPE) { + Obj.PeHeader.SizeOfHeaders = SizeOfHeaders; + Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData; + + if (!Obj.Sections.empty()) { + const Section &S = Obj.Sections.back(); + Obj.PeHeader.SizeOfImage = + alignTo(S.Header.VirtualAddress + S.Header.VirtualSize, + Obj.PeHeader.SectionAlignment); + } + + // If the PE header had a checksum, clear it, since it isn't valid + // any longer. (We don't calculate a new one.) + Obj.PeHeader.CheckSum = 0; + } + + size_t StrTabSize = finalizeStringTable(); + size_t SymTabSize, SymbolSize; + std::tie(SymTabSize, SymbolSize) = IsBigObj + ? finalizeSymbolTable() + : finalizeSymbolTable(); + + size_t PointerToSymbolTable = FileSize; + // StrTabSize <= 4 is the size of an empty string table, only consisting + // of the length field. + if (SymTabSize == 0 && StrTabSize <= 4) { + // Don't point to the symbol table if empty. + PointerToSymbolTable = 0; + // For executables, skip the length field of an empty string table. + if (Obj.IsPE) + StrTabSize = 0; + } + + size_t NumRawSymbols = SymTabSize / SymbolSize; + Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable; + Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols; + FileSize += SymTabSize + StrTabSize; + FileSize = alignTo(FileSize, FileAlignment); +} + +void COFFWriter::writeHeaders(bool IsBigObj) { + uint8_t *Ptr = Buf.getBufferStart(); + if (Obj.IsPE) { + memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader)); + Ptr += sizeof(Obj.DosHeader); + memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size()); + Ptr += Obj.DosStub.size(); + memcpy(Ptr, PEMagic, sizeof(PEMagic)); + Ptr += sizeof(PEMagic); + } + if (!IsBigObj) { + memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader)); + Ptr += sizeof(Obj.CoffFileHeader); + } else { + // Generate a coff_bigobj_file_header, filling it in with the values + // from Obj.CoffFileHeader. All extra fields that don't exist in + // coff_file_header can be set to hardcoded values. + coff_bigobj_file_header BigObjHeader; + BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN; + BigObjHeader.Sig2 = 0xffff; + BigObjHeader.Version = BigObjHeader::MinBigObjectVersion; + BigObjHeader.Machine = Obj.CoffFileHeader.Machine; + BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp; + memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic)); + BigObjHeader.unused1 = 0; + BigObjHeader.unused2 = 0; + BigObjHeader.unused3 = 0; + BigObjHeader.unused4 = 0; + // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus + // get the original one instead. + BigObjHeader.NumberOfSections = Obj.Sections.size(); + BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable; + BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols; + + memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader)); + Ptr += sizeof(BigObjHeader); + } + if (Obj.IsPE) { + if (Obj.Is64) { + memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader)); + Ptr += sizeof(Obj.PeHeader); + } else { + pe32_header PeHeader; + copyPeHeader(PeHeader, Obj.PeHeader); + // The pe32plus_header (stored in Object) lacks the BaseOfData field. + PeHeader.BaseOfData = Obj.BaseOfData; + + memcpy(Ptr, &PeHeader, sizeof(PeHeader)); + Ptr += sizeof(PeHeader); + } + for (const auto &DD : Obj.DataDirectories) { + memcpy(Ptr, &DD, sizeof(DD)); + Ptr += sizeof(DD); + } + } + for (const auto &S : Obj.Sections) { + memcpy(Ptr, &S.Header, sizeof(S.Header)); + Ptr += sizeof(S.Header); + } +} + +void COFFWriter::writeSections() { + for (const auto &S : Obj.Sections) { + uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData; + memcpy(Ptr, S.Contents.data(), S.Contents.size()); + + // For executable sections, pad the remainder of the raw data size with + // 0xcc, which is int3 on x86. + if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) && + S.Header.SizeOfRawData > S.Contents.size()) + memset(Ptr + S.Contents.size(), 0xcc, + S.Header.SizeOfRawData - S.Contents.size()); + + Ptr += S.Header.SizeOfRawData; + memcpy(Ptr, S.Relocs.data(), S.Relocs.size() * sizeof(coff_relocation)); + } +} + +template void COFFWriter::writeSymbolStringTables() { + uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable; + for (const auto &S : Obj.Symbols) { + // Convert symbols back to the right size, from coff_symbol32. + copySymbol(*reinterpret_cast(Ptr), + S.Sym); + Ptr += sizeof(SymbolTy); + memcpy(Ptr, S.AuxData.data(), S.AuxData.size()); + Ptr += S.AuxData.size(); + } + if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) { + // Always write a string table in object files, even an empty one. + StrTabBuilder.write(Ptr); + Ptr += StrTabBuilder.getSize(); + } +} + +void COFFWriter::write(bool IsBigObj) { + finalize(IsBigObj); + + Buf.allocate(FileSize); + + writeHeaders(IsBigObj); + writeSections(); + if (IsBigObj) + writeSymbolStringTables(); + else + writeSymbolStringTables(); + + if (Obj.IsPE) + patchDebugDirectory(); + + if (auto E = Buf.commit()) + reportError(Buf.getName(), errorToErrorCode(std::move(E))); +} + +// Locate which sections contain the debug directories, iterate over all +// the debug_directory structs in there, and set the PointerToRawData field +// in all of them, according to their new physical location in the file. +void COFFWriter::patchDebugDirectory() { + if (Obj.DataDirectories.size() < DEBUG_DIRECTORY) + return; + const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY]; + if (Dir->Size <= 0) + return; + for (const auto &S : Obj.Sections) { + if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress && + Dir->RelativeVirtualAddress < + S.Header.VirtualAddress + S.Header.SizeOfRawData) { + if (Dir->RelativeVirtualAddress + Dir->Size > + S.Header.VirtualAddress + S.Header.SizeOfRawData) + reportError(Buf.getName(), + make_error( + "Debug directory extends past end of section", + object_error::parse_failed)); + + size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress; + uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset; + uint8_t *End = Ptr + Dir->Size; + while (Ptr < End) { + debug_directory *Debug = reinterpret_cast(Ptr); + Debug->PointerToRawData = + S.Header.PointerToRawData + Offset + sizeof(debug_directory); + Ptr += sizeof(debug_directory) + Debug->SizeOfData; + Offset += sizeof(debug_directory) + Debug->SizeOfData; + } + // Debug directory found and patched, all done. + return; + } + } + reportError(Buf.getName(), + make_error("Debug directory not found", + object_error::parse_failed)); +} + +void COFFWriter::write() { + bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16; + if (IsBigObj && Obj.IsPE) + reportError(Buf.getName(), + make_error("Too many sections for executable", + object_error::parse_failed)); + write(IsBigObj); +} + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -9,6 +9,7 @@ #include "llvm-objcopy.h" #include "Buffer.h" +#include "COFF/COFFObjcopy.h" #include "CopyConfig.h" #include "ELF/ELFObjcopy.h" @@ -19,6 +20,7 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Object/Error.h" @@ -125,6 +127,8 @@ Buffer &Out) { if (auto *ELFBinary = dyn_cast(&In)) return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); + else if (auto *COFFBinary = dyn_cast(&In)) + return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out); else error("Unsupported object file format"); }