Index: test/tools/llvm-objcopy/COFF/Inputs/x86_64-debug-exe.yaml =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/Inputs/x86_64-debug-exe.yaml @@ -0,0 +1,203 @@ +--- !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: 20480 + Size: 24 + CertificateTable: + RelativeVirtualAddress: 0 + Size: 0 + BaseRelocationTable: + RelativeVirtualAddress: 0 + Size: 0 + Debug: + RelativeVirtualAddress: 12288 + Size: 28 + 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: 50894C24048B0DF52F0000034C240489C859C3662E0F1F8400000000000F1F00C3662E0F1F8400000000000F1F440000554883EC30488D6C2430E8E1FFFFFFC745FC00000000B902000000E8B0FFFFFF904883C4305DC3 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 52 + SectionData: FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF00000000000000000101010001020000010A03350A03055201500000 + - Name: .buildid + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 53 + SectionData: 000000007C39FD5B0000000002000000190000001C3000001C0800005253445308D09F90668CDB1D4C4C44205044422E0100000000 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 16384 + VirtualSize: 4 + SectionData: '01000000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 20480 + VirtualSize: 24 + SectionData: '001000001310000020200000301000005710000028200000' + - Name: .debug_abbrev + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 24576 + VirtualSize: 126 + SectionData: 011101250E1305030E10171B0E110112060000023400030E49133A0B3B0B02180000032400030E3E0B0B0B0000042E01110112064018030E3A0B3B0B271949133F1900000505000218030E3A0B3B0B49130000062E00110112064018030E3A0B3B0B27193F190000072E00110112064018030E3A0B3B0B49133F19000000 + - Name: .debug_info + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 28672 + VirtualSize: 157 + SectionData: 990000000400000000000801000000000C00370000000000000040000000001000400100000057000000026B0000003F000000010109030040004001000000036D00000005040400100040010000001300000001577100000001033F000000050291047F00000001033F000000000620100040010000000100000001577300000001070730100040010000002700000001567A00000001093F00000000 + - Name: .debug_line + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 32768 + VirtualSize: 91 + SectionData: 57000000040020000000010101FB0E0D00010101010000000100000100736F757263652E630000000000000902001000400100000014050A0A59050C066605034A050006081505010A130500F3050A0A08590503069E0207000101 + - Name: .debug_macinfo + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 36864 + VirtualSize: 1 + SectionData: '00' + - Name: .debug_str + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 40960 + VirtualSize: 129 + SectionData: 636C616E672076657273696F6E20382E302E3020287472756E6B203334363337382920286C6C766D2F7472756E6B203334363339302900736F757263652E63002F686F6D652F6D617274696E2F636F64652F6C6C766D2F6275696C642F6F626A636F70792D696E707574007800696E740066005F5F6D61696E006D61696E007900 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .data + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .bss + Value: 4 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .xdata + Value: 32 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .debug_str + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .debug_abbrev + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .debug_info + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .debug_macinfo + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .debug_line + Value: 0 + SectionNumber: 8 + 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: 4 + 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/X86/lit.local.cfg =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/lit.local.cfg @@ -0,0 +1,4 @@ +# These tests require a registered x86 backend. + +if not 'X86' in config.root.targets: + config.unsupported = True Index: test/tools/llvm-objcopy/COFF/X86/remove-local-symbols.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-local-symbols.s @@ -0,0 +1,37 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o + +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE +# RUN: llvm-strip -x %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-POST + +# RELOCS: Relocations [ +# RELOCS-NEXT: Section (1) .text { +# RELOCS-NEXT: 0x2 IMAGE_REL_AMD64_REL32 ptr +# RELOCS-NEXT: } +# RELOCS-NEXT: ] + +# SYMBOLS-PRE: 00000000 T mainfunc +# SYMBOLS-PRE: 0000000c t otherfunc +# SYMBOLS-PRE: 00000000 d ptr +# SYMBOLS-PRE-EMPTY: + +# SYMBOLS-POST: 00000000 T mainfunc +# SYMBOLS-POST: 00000000 d ptr +# SYMBOLS-POST-EMPTY: + + + .text + .globl mainfunc +mainfunc: + movl ptr(%rip), %eax + # This doesn't produce any relocation, and otherfunc can be dropped. + call otherfunc + ret +otherfunc: + ret + + .data +ptr: + .long 42 Index: test/tools/llvm-objcopy/COFF/X86/remove-section1.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-section1.s @@ -0,0 +1,34 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o + +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE +# RUN: llvm-objcopy -R .data %t.o +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-POST + +# SYMBOLS-PRE: 00000000 T mainfunc +# SYMBOLS-PRE: 00000001 T otherfunc +# SYMBOLS-PRE: 00000002 T otherfunc2 +# SYMBOLS-PRE: 00000000 D ptr +# SYMBOLS-PRE-EMPTY: + +# SYMBOLS-POST: 00000000 T mainfunc +# SYMBOLS-POST: 00000001 T otherfunc +# SYMBOLS-POST: 00000002 T otherfunc2 +# SYMBOLS-POST-NOT: ptr +# SYMBOLS-POST-EMPTY: + + + .text + .globl mainfunc +mainfunc: + ret + .globl otherfunc +otherfunc: + ret + .globl otherfunc2 +otherfunc2: + ret + + .data + .globl ptr +ptr: + .long 42 Index: test/tools/llvm-objcopy/COFF/X86/remove-section2.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-section2.s @@ -0,0 +1,25 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o + +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS +# RUN: not llvm-objcopy -R .data %t.o 2>&1 | FileCheck %s --check-prefix=ERROR + +# RELOCS: Relocations [ +# RELOCS-NEXT: Section (1) .text { +# RELOCS-NEXT: 0x2 IMAGE_REL_AMD64_REL32 ptr +# RELOCS-NEXT: } +# RELOCS-NEXT: ] + +# GNU objcopy doesn't error out here, but instead changes the relocation +# target to the .text symbol instead. + +# ERROR: Relocation to removed symbol ptr + + .text + .globl mainfunc +mainfunc: + movl ptr(%rip), %eax + ret + + .data +ptr: + .long 42 Index: test/tools/llvm-objcopy/COFF/X86/remove-symbol1.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-symbol1.s @@ -0,0 +1,43 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o + +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE +# RUN: llvm-objcopy -N otherfunc %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck %s --check-prefix=RELOCS +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-POST + +# RELOCS: Relocations [ +# RELOCS-NEXT: Section (1) .text { +# RELOCS-NEXT: 0x2 IMAGE_REL_AMD64_REL32 ptr +# RELOCS-NEXT: } +# RELOCS-NEXT: ] + +# SYMBOLS-PRE: 00000000 T mainfunc +# SYMBOLS-PRE: 0000000c T otherfunc +# SYMBOLS-PRE: 0000000d T otherfunc2 +# SYMBOLS-PRE: 00000000 d ptr +# SYMBOLS-PRE-EMPTY: + +# SYMBOLS-POST: 00000000 T mainfunc +# SYMBOLS-POST-NOT: otherfunc +# SYMBOLS-POST: 0000000d T otherfunc2 +# SYMBOLS-POST: 00000000 d ptr +# SYMBOLS-POST-EMPTY: + + + .text + .globl mainfunc +mainfunc: + movl ptr(%rip), %eax + call otherfunc + ret + .globl otherfunc +otherfunc: + ret + .globl otherfunc2 +otherfunc2: + ret + + .data +ptr: + .long 42 Index: test/tools/llvm-objcopy/COFF/X86/remove-symbol2.s =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/X86/remove-symbol2.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o + +# RUN: llvm-nm %t.o | FileCheck %s --check-prefix=SYMBOLS-PRE +# RUN: not llvm-objcopy -N ptr %t.o 2>&1 | FileCheck %s --check-prefix=ERROR + +# SYMBOLS-PRE: 00000000 T mainfunc +# SYMBOLS-PRE: 0000000c T otherfunc +# SYMBOLS-PRE: 0000000d T otherfunc2 +# SYMBOLS-PRE: 00000000 d ptr +# SYMBOLS-PRE-EMPTY: + +# ERROR: Can't remove referenced symbol ptr + + .text + .globl mainfunc +mainfunc: + movl ptr(%rip), %eax + call otherfunc + ret + .globl otherfunc +otherfunc: + ret + .globl otherfunc2 +otherfunc2: + ret + + .data +ptr: + .long 42 Index: test/tools/llvm-objcopy/COFF/discard-all.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/discard-all.test @@ -0,0 +1,87 @@ +RUN: yaml2obj %p/Inputs/x86_64-obj.yaml > %t.o +RUN: llvm-readobj -symbols %t.o | FileCheck %s --check-prefix=SYMS-ORIG + +RUN: llvm-strip -x %t.o +RUN: llvm-readobj -symbols %t.o | FileCheck %s --check-prefix=SYMS-NEW + +RUN: llvm-readobj -sections %t.o | FileCheck %s --check-prefix=SECTIONS + +For this specific input, the debug sections and symbols relating +to the debug sections are removed. + +SYMS-ORIG: Name: .text +SYMS-ORIG: Name: .data +SYMS-ORIG: Name: .bss +SYMS-ORIG: Name: .xdata +SYMS-ORIG: Name: .debug_str +SYMS-ORIG: Name: .debug_abbrev +SYMS-ORIG: Name: .debug_info +SYMS-ORIG: Name: .debug_macinfo +SYMS-ORIG: Name: .pdata +SYMS-ORIG: Name: .debug_line +SYMS-ORIG: Name: .llvm_addrsig +SYMS-ORIG: Name: @feat.00 +SYMS-ORIG: Name: f +SYMS-ORIG: Name: x +SYMS-ORIG: Name: __main +SYMS-ORIG: Name: main + +SYMS-NEW-NOT: Name: .text +SYMS-NEW-NOT: Name: .data +SYMS-NEW-NOT: Name: .bss +SYMS-NEW: Name: .xdata +SYMS-NEW-NOT: Name: .debug_str +SYMS-NEW-NOT: Name: .debug_abbrev +SYMS-NEW-NOT: Name: .debug_info +SYMS-NEW-NOT: Name: .debug_macinfo +SYMS-NEW-NOT: Name: .pdata +SYMS-NEW-NOT: Name: .debug_line +SYMS-NEW-NOT: Name: .llvm_addrsig +SYMS-NEW-NOT: Name: @feat.00 +SYMS-NEW: Name: f +SYMS-NEW: Name: x +SYMS-NEW: Name: __main +SYMS-NEW: Name: main + +SECTIONS: Sections [ +SECTIONS-NEXT: Section { +SECTIONS-NEXT: Number: 1 +SECTIONS-NEXT: Name: .text +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 87 +SECTIONS: Section { +SECTIONS-NEXT: Number: 2 +SECTIONS-NEXT: Name: .data +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 4 +SECTIONS: Section { +SECTIONS-NEXT: Number: 3 +SECTIONS-NEXT: Name: .bss +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 0 +SECTIONS: Section { +SECTIONS-NEXT: Number: 4 +SECTIONS-NEXT: Name: .xdata +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 20 +SECTIONS: Section { +SECTIONS-NEXT: Number: 5 +SECTIONS-NEXT: Name: .pdata +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 24 +SECTIONS: Section { +SECTIONS-NEXT: Number: 6 +SECTIONS-NEXT: Name: .llvm_addrsig +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 2 +SECTIONS-NOT: Name: .debug_abbrev +SECTIONS-NOT: Name: .debug_info +SECTIONS-NOT: Name: .debug_line +SECTIONS-NOT: Name: .debug_macinfo +SECTIONS-NOT: Name: .debug_str Index: test/tools/llvm-objcopy/COFF/strip-executable.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/strip-executable.test @@ -0,0 +1,71 @@ +RUN: yaml2obj %p/Inputs/x86_64-debug-exe.yaml > %t.input.exe +RUN: llvm-nm %t.input.exe | FileCheck %s --check-prefix=SYMS-ORIG + +RUN: llvm-objcopy --strip-all %t.input.exe %t.exe +RUN: llvm-nm %t.exe 2>&1 | FileCheck %s --check-prefix=SYMS-NEW +RUN: llvm-readobj -sections %t.exe | FileCheck %s --check-prefix=SECTIONS + +RUN: llvm-objcopy --strip-unneeded %t.input.exe %t.exe +RUN: llvm-nm %t.exe 2>&1 | FileCheck %s --check-prefix=SYMS-NEW +RUN: llvm-readobj -sections %t.exe | FileCheck %s --check-prefix=SECTIONS + +RUN: cp %t.input.exe %t.exe +RUN: llvm-strip %t.exe +RUN: llvm-nm %t.exe 2>&1 | FileCheck %s --check-prefix=SYMS-NEW +RUN: llvm-readobj -sections %t.exe | FileCheck %s --check-prefix=SECTIONS + +The debug sections and all symbols are removed. + +SYMS-ORIG: 40004004 d .bss +SYMS-ORIG: 40004000 d .data +SYMS-ORIG: 40006000 N .debug_abbrev +SYMS-ORIG: 40007000 N .debug_info +SYMS-ORIG: 40008000 N .debug_line +SYMS-ORIG: 40009000 N .debug_macinfo +SYMS-ORIG: 4000a000 N .debug_str +SYMS-ORIG: 40005000 r .pdata +SYMS-ORIG: 40001000 t .text +SYMS-ORIG: 40002020 r .xdata +SYMS-ORIG: 40001020 T __main +SYMS-ORIG: 40001000 T f +SYMS-ORIG: 40001030 T main +SYMS-ORIG: 40004000 d x + +SYMS-NEW: no symbols + +SECTIONS: Sections [ +SECTIONS-NEXT: Section { +SECTIONS-NEXT: Number: 1 +SECTIONS-NEXT: Name: .text +SECTIONS-NEXT: VirtualSize: 0x57 +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 512 +SECTIONS: Section { +SECTIONS-NEXT: Number: 2 +SECTIONS-NEXT: Name: .rdata +SECTIONS-NEXT: VirtualSize: 0x34 +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 512 +SECTIONS: Section { +SECTIONS-NEXT: Number: 3 +SECTIONS-NEXT: Name: .buildid +SECTIONS-NEXT: VirtualSize: 0x35 +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 512 +SECTIONS: Section { +SECTIONS-NEXT: Number: 4 +SECTIONS-NEXT: Name: .data +SECTIONS-NEXT: VirtualSize: 0x4 +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 512 +SECTIONS: Section { +SECTIONS-NEXT: Number: 5 +SECTIONS-NEXT: Name: .pdata +SECTIONS-NEXT: VirtualSize: 0x18 +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 512 +SECTIONS-NOT: Name: .debug_abbrev +SECTIONS-NOT: Name: .debug_info +SECTIONS-NOT: Name: .debug_line +SECTIONS-NOT: Name: .debug_macinfo +SECTIONS-NOT: Name: .debug_str Index: test/tools/llvm-objcopy/COFF/strip-object.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/COFF/strip-object.test @@ -0,0 +1,87 @@ +RUN: yaml2obj %p/Inputs/x86_64-obj.yaml > %t.input.o +RUN: llvm-readobj -symbols %t.input.o | FileCheck %s --check-prefix=SYMS-ORIG + +RUN: llvm-objcopy --strip-debug %t.input.o %t.o +RUN: llvm-readobj -symbols %t.o | FileCheck %s --check-prefix=SYMS-NEW + +RUN: llvm-readobj -sections %t.o | FileCheck %s --check-prefix=SECTIONS + +The debug sections are removed, symbols relating to the debug sections +are removed. + +SYMS-ORIG: Name: .text +SYMS-ORIG: Name: .data +SYMS-ORIG: Name: .bss +SYMS-ORIG: Name: .xdata +SYMS-ORIG: Name: .debug_str +SYMS-ORIG: Name: .debug_abbrev +SYMS-ORIG: Name: .debug_info +SYMS-ORIG: Name: .debug_macinfo +SYMS-ORIG: Name: .pdata +SYMS-ORIG: Name: .debug_line +SYMS-ORIG: Name: .llvm_addrsig +SYMS-ORIG: Name: @feat.00 +SYMS-ORIG: Name: f +SYMS-ORIG: Name: x +SYMS-ORIG: Name: __main +SYMS-ORIG: Name: main + +SYMS-NEW: Name: .text +SYMS-NEW: Name: .data +SYMS-NEW: Name: .bss +SYMS-NEW: Name: .xdata +SYMS-NEW-NOT: Name: .debug_str +SYMS-NEW-NOT: Name: .debug_abbrev +SYMS-NEW-NOT: Name: .debug_info +SYMS-NEW-NOT: Name: .debug_macinfo +SYMS-NEW: Name: .pdata +SYMS-NEW-NOT: Name: .debug_line +SYMS-NEW: Name: .llvm_addrsig +SYMS-NEW: Name: @feat.00 +SYMS-NEW: Name: f +SYMS-NEW: Name: x +SYMS-NEW: Name: __main +SYMS-NEW: Name: main + +SECTIONS: Sections [ +SECTIONS-NEXT: Section { +SECTIONS-NEXT: Number: 1 +SECTIONS-NEXT: Name: .text +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 87 +SECTIONS: Section { +SECTIONS-NEXT: Number: 2 +SECTIONS-NEXT: Name: .data +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 4 +SECTIONS: Section { +SECTIONS-NEXT: Number: 3 +SECTIONS-NEXT: Name: .bss +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 0 +SECTIONS: Section { +SECTIONS-NEXT: Number: 4 +SECTIONS-NEXT: Name: .xdata +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 20 +SECTIONS: Section { +SECTIONS-NEXT: Number: 5 +SECTIONS-NEXT: Name: .pdata +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 24 +SECTIONS: Section { +SECTIONS-NEXT: Number: 6 +SECTIONS-NEXT: Name: .llvm_addrsig +SECTIONS-NEXT: VirtualSize: +SECTIONS-NEXT: VirtualAddress: +SECTIONS-NEXT: RawDataSize: 2 +SECTIONS-NOT: Name: .debug_abbrev +SECTIONS-NOT: Name: .debug_info +SECTIONS-NOT: Name: .debug_line +SECTIONS-NOT: Name: .debug_macinfo +SECTIONS-NOT: Name: .debug_str Index: tools/llvm-objcopy/CMakeLists.txt =================================================================== --- tools/llvm-objcopy/CMakeLists.txt +++ tools/llvm-objcopy/CMakeLists.txt @@ -18,6 +18,7 @@ CopyConfig.cpp llvm-objcopy.cpp COFF/COFFObjcopy.cpp + COFF/Object.cpp COFF/Reader.cpp COFF/Writer.cpp ELF/ELFObjcopy.cpp Index: tools/llvm-objcopy/COFF/COFFObjcopy.cpp =================================================================== --- tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ tools/llvm-objcopy/COFF/COFFObjcopy.cpp @@ -15,8 +15,13 @@ #include "Writer.h" #include "llvm-objcopy.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/JamCRC.h" +#include "llvm/Support/Path.h" #include namespace llvm { @@ -26,11 +31,151 @@ using namespace object; using namespace COFF; +static bool isDebugSection(const Section &Sec) { + return Sec.Name.startswith(".debug"); +} + +static void handleArgs(const CopyConfig &Config, Object &Obj) { + size_t OrigNumSymbols = Obj.Symbols.size(); + // Initialize mappings for the relocations. Relocations refer to symbols + // by index, which has to be remapped and updated after removing symbols. + Obj.initRawSymbolTable(); + Obj.initRelocTargets(Config.InputFilename); + + std::function RemovePred = [](const Section &) { + return false; + }; + + // Removes: + if (!Config.ToRemove.empty()) { + RemovePred = [&Config](const Section &Sec) { + return is_contained(Config.ToRemove, Sec.Name); + }; + } + + if (Config.StripAllGNU || Config.StripDebug || Config.StripAll || + Config.DiscardAll || Config.StripUnneeded) { + RemovePred = [RemovePred](const Section &Sec) { + return RemovePred(Sec) || isDebugSection(Sec); + }; + } + + // Explicit copies: + if (!Config.OnlySection.empty()) { + RemovePred = [&Config, &Obj](const Section &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (is_contained(Config.OnlySection, Sec.Name)) + return false; + + // Remove everything else. In case there are special sections we always + // want to keep, we would check RemovePred first and then check for + // the special sections, before returning true here. + return true; + }; + } + + if (!Config.KeepSection.empty()) { + RemovePred = [&Config, RemovePred](const Section &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (is_contained(Config.KeepSection, Sec.Name)) + return false; + // Otherwise defer to RemovePred. + return RemovePred(Sec); + }; + } + + size_t SecIdx = 1; + for (Section &Sec : Obj.Sections) + Sec.Idx = SecIdx++; + + DenseSet RemovedSections; + RemovePred = [&RemovedSections, RemovePred](const Section &Sec) { + // A no-op lambda wrapper, that keeps track of which sections actually + // were removed. + bool Remove = RemovePred(Sec); + if (Remove) + RemovedSections.insert(Sec.Idx); + return Remove; + }; + + // Perform the actual section removals. + Obj.removeSections(RemovePred); + + // If we need to do per-symbol removals, initialize the Referenced field, + // based on the remaining sections. The setReferencedSymbols method can + // be used only before removing any symbols. + if (Config.StripUnneeded || Config.DiscardAll || + !Config.SymbolsToRemove.empty()) + Obj.setReferencedSymbols(Config.InputFilename); + + // If we did remove sections, remove all symbols pointing to those sections + // and update symbols to point to new section numbers. + + // NOTE: We don't update section number references in + // coff_aux_section_definition for associative comdats pointing behind + // removed sections. Config.StripUnneeded or Config.DiscardAll will likely + // also break comdats. + if (!RemovedSections.empty()) { + // Initialize a mapping from old to new section indices. + DenseMap NewSectionIndex; + SecIdx = 1; + for (Section &Sec : Obj.Sections) { + NewSectionIndex[Sec.Idx] = SecIdx; + Sec.Idx = SecIdx++; + } + // Remove all symbols where the section number exists in RemovedSections. + Obj.removeSymbols([&](const Symbol &Sym) { + return RemovedSections.count(Sym.Sym.SectionNumber) == 1; + }); + // Update SectionNumber to point to the new section indices. + for (Symbol &Sym : Obj.Symbols) + Sym.Sym.SectionNumber = NewSectionIndex[Sym.Sym.SectionNumber]; + } + + // Actually do removals of symbols. + Obj.removeSymbols([&](const Symbol &Sym) { + if (!Config.SymbolsToKeep.empty() && + is_contained(Config.SymbolsToKeep, Sym.Name)) + return false; + + if (Config.StripAll || Config.StripAllGNU) + return true; + + if (!Config.SymbolsToRemove.empty() && + is_contained(Config.SymbolsToRemove, Sym.Name)) { + // Explicitly removing a referenced symbol is an error, while + // implicitly removing them as part of a blanket removal above is + // accepted. + if (Sym.Referenced) + reportError(Config.OutputFilename, + make_error("Can't remove referenced symbol " + + Sym.Name, + object_error::parse_failed)); + return true; + } + + // GNU binutils objcopy keeps referenced local symbols if Config.DiscaredAll + // is set. + if ((Config.StripUnneeded || Config.DiscardAll) && !Sym.Referenced && + (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC || Obj.IsPE)) + return true; + + return false; + }); + + // If the number of symbols have changed, either by removing symbols + // from removed sections, or explicitly removing symbols, update relocations + // accordingly. + if (Obj.Symbols.size() != OrigNumSymbols) + Obj.updateRelocTargets(Config.OutputFilename); +} + 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"); + handleArgs(Config, *Obj); COFFWriter Writer(*Obj, Out); Writer.write(); } Index: tools/llvm-objcopy/COFF/Object.h =================================================================== --- tools/llvm-objcopy/COFF/Object.h +++ tools/llvm-objcopy/COFF/Object.h @@ -27,12 +27,21 @@ ArrayRef Contents; std::vector Relocs; StringRef Name; + + // Fields used by some transformations in objcopy, but not necessary + // for actually writing back to a file. + std::vector RelocTargets; + size_t Idx; }; struct Symbol { object::coff_symbol32 Sym; StringRef Name; ArrayRef AuxData; + + // Fields used by some transformations in objcopy, but not necessary + // for actually writing back to a file. + bool Referenced = false; }; struct Object { @@ -50,6 +59,20 @@ std::vector DataDirectories; std::vector
Sections; std::vector Symbols; + + // Fields used for transformations in objcopy, but not necessary + // for actually writing back to a file. + std::vector RawSymbolTable; + + void removeSymbols(function_ref ToRemove); + void removeSections(function_ref ToRemove); + + // StringRef taken as parameter for error reporting. + void initRawSymbolTable(); + void setReferencedSymbols(StringRef Filename); + + void initRelocTargets(StringRef Filename); + void updateRelocTargets(StringRef Filename); }; // Copy between coff_symbol16 and coff_symbol32. Index: tools/llvm-objcopy/COFF/Object.cpp =================================================================== --- /dev/null +++ tools/llvm-objcopy/COFF/Object.cpp @@ -0,0 +1,115 @@ +//===- Object.cpp ---------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Object.h" +#include "llvm-objcopy.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" +#include +#include +#include + +namespace llvm { +namespace objcopy { +namespace coff { + +using namespace object; + +void Object::removeSymbols(function_ref ToRemove) { + Symbols.erase( + std::remove_if(std::begin(Symbols), std::end(Symbols), + [ToRemove](const Symbol &Sym) { return ToRemove(Sym); }), + std::end(Symbols)); + RawSymbolTable.clear(); +} + +void Object::removeSections(function_ref ToRemove) { + Sections.erase( + std::remove_if(std::begin(Sections), std::end(Sections), + [ToRemove](const Section &Sec) { return ToRemove(Sec); }), + std::end(Sections)); +} + +void Object::initRawSymbolTable() { + for (Symbol &S : Symbols) { + RawSymbolTable.push_back(&S); + for (size_t I = 0; I < S.Sym.NumberOfAuxSymbols; I++) + RawSymbolTable.push_back(nullptr); + } +} + +void Object::setReferencedSymbols(StringRef Filename) { + // This function is meant to be used before pruning any symbols. + // It uses raw symbol indexes from Reloc.SymbolTableIndex instead of + // looking things up using the symbol names. (After pruning the symbol + // table, this would need to use a StringMap for finding the right symbols, + // like updateRelocTargets below.) + assert(RawSymbolTable.size() == CoffFileHeader.NumberOfSymbols); + for (const Section &Sec : Sections) { + for (const coff_relocation &Reloc : Sec.Relocs) { + if (Reloc.SymbolTableIndex >= RawSymbolTable.size()) + reportError(Filename, + make_error("SymbolTableIndex out of range", + object_error::parse_failed)); + else if (RawSymbolTable[Reloc.SymbolTableIndex] == nullptr) + reportError(Filename, + make_error("Invalid SymbolTableIndex", + object_error::parse_failed)); + RawSymbolTable[Reloc.SymbolTableIndex]->Referenced = true; + } + } +} + +void Object::initRelocTargets(StringRef Filename) { + // This function must be called before pruning any symbols. + assert(RawSymbolTable.size() == CoffFileHeader.NumberOfSymbols); + for (Section &Sec : Sections) { + for (const coff_relocation &Reloc : Sec.Relocs) { + if (Reloc.SymbolTableIndex >= RawSymbolTable.size()) + reportError(Filename, + make_error("SymbolTableIndex out of range", + object_error::parse_failed)); + else if (RawSymbolTable[Reloc.SymbolTableIndex] == nullptr) + reportError(Filename, + make_error("Invalid SymbolTableIndex", + object_error::parse_failed)); + Sec.RelocTargets.push_back(RawSymbolTable[Reloc.SymbolTableIndex]->Name); + } + } +} + +void Object::updateRelocTargets(StringRef Filename) { + // Initialize a mapping from symbol name to raw symbol index. + StringMap SymMap; + uint32_t RawSymIdx = 0; + for (const Symbol &Sym : Symbols) { + SymMap[Sym.Name] = RawSymIdx; + RawSymIdx += 1 + Sym.Sym.NumberOfAuxSymbols; + } + // Update relocations with new symbol indices, or error out if the + // target symbol can't be found. + for (Section &Sec : Sections) { + assert(Sec.Relocs.size() == Sec.RelocTargets.size()); + for (size_t I = 0, E = Sec.Relocs.size(); I < E; I++) { + auto It = SymMap.find(Sec.RelocTargets[I]); + if (It != SymMap.end()) + Sec.Relocs[I].SymbolTableIndex = It->second; + else + reportError(Filename, + make_error("Relocation to removed symbol " + + Sec.RelocTargets[I], + object_error::parse_failed)); + } + } +} + +} // end namespace coff +} // end namespace objcopy +} // end namespace llvm