diff --git a/llvm/test/tools/llvm-readobj/COFF/Inputs/pseudoreloc.i386.yaml b/llvm/test/tools/llvm-readobj/COFF/Inputs/pseudoreloc.i386.yaml new file mode 100644 index 0000000000000..9eb56dd7f9794 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/Inputs/pseudoreloc.i386.yaml @@ -0,0 +1,123 @@ +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4096 + 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_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 0 + Size: 0 + ImportTable: + RelativeVirtualAddress: 8288 + Size: 60 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 0 + Size: 0 + 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: 8368 + Size: 20 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ IMAGE_FILE_RELOCS_STRIPPED, 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: 60 + SectionData: A1003040000FBE008B0D043040000FBE0901C1A1083040000FBE10A1103040000FBE0001D001C8C39090909090909090A1502040002B0508204000C3 + SizeOfRawData: 512 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 254 + SectionData: 3377115566228844000000000000000001000000[[SYMBOL0=B0200000]]0030000020000000[[SYMBOL1=B4200000]]0430000020000000[[SYMBOL2=BC200000]]0830000020000000BC2000000C30000020000000B02000001030000020000000FFFFFFFF00000000FFFFFFFF000000009C2000000000000000000000DC200000B0200000A82000000000000000000000ED200000BC2000000000000000000000000000000000000000000000C4200000CC20000000000000D420000000000000C4200000CC20000000000000D420000000000000000073796D310000000073796D320000000073796D3300006578706F7274312E693338362E646C6C006578706F7274322E693338362E646C6C00 + SizeOfRawData: 512 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 12288 + VirtualSize: 20 + SectionData: B1204000B6204000BD204000BD204000B2204000 + SizeOfRawData: 512 +symbols: + - Name: _start + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _local2a + Value: 4 + SectionNumber: [[SECTION_OF_LOCAL2A=3]] + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _local3a + Value: 8 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __pei386_runtime_relocator + Value: 48 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: ___RUNTIME_PSEUDO_RELOC_LIST_END__ + Value: [[END=80]] + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: ___RUNTIME_PSEUDO_RELOC_LIST__ + Value: [[BEGIN=8]] + SectionNumber: [[SECTION_OF_BEGIN=2]] + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/llvm/test/tools/llvm-readobj/COFF/Inputs/pseudoreloc.x86_64.yaml b/llvm/test/tools/llvm-readobj/COFF/Inputs/pseudoreloc.x86_64.yaml new file mode 100644 index 0000000000000..e31f61c17fd3d --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/Inputs/pseudoreloc.x86_64.yaml @@ -0,0 +1,123 @@ +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 4096 + ImageBase: 5368709120 + 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_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 0 + Size: 0 + ImportTable: + RelativeVirtualAddress: 8304 + Size: 60 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 0 + Size: 0 + 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: 8408 + Size: 40 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_RELOCS_STRIPPED, 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: 61 + SectionData: 488B05F91F00000FBE00488B0DF71F00000FBE0901C1488B05F31F00000FBE10488B05F91F00000FBE0001D001C8C3908B051A1000002B05CC0F0000C3 + SizeOfRawData: 512 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 318 + SectionData: 3377115566228844000000000000000001000000[[SYMBOL0=E8200000]]0030000040000000[[SYMBOL1=F0200000]]0830000040000000[[SYMBOL2=D8200000]]1030000040000000D82000001830000040000000E82000002030000040000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000B0200000000000000000000018210000D8200000C020000000000000000000002B210000E82000000000000000000000000000000000000000000000000000000021000000000000000000000000000008210000000000001021000000000000000000000000000000210000000000000000000000000000082100000000000010210000000000000000000000000000000073796D330000000073796D310000000073796D3200006578706F7274322E7838365F36342E646C6C006578706F7274312E7838365F36342E646C6C00 + SizeOfRawData: 512 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 12288 + VirtualSize: 40 + SectionData: E920004001000000F220004001000000D920004001000000D920004001000000EA20004001000000 + SizeOfRawData: 512 +symbols: + - Name: start + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: local2a + Value: 8 + SectionNumber: [[SECTION_OF_LOCAL2A=3]] + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: local3a + Value: 16 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _pei386_runtime_relocator + Value: 48 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __RUNTIME_PSEUDO_RELOC_LIST_END__ + Value: [[END=80]] + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __RUNTIME_PSEUDO_RELOC_LIST__ + Value: [[BEGIN=8]] + SectionNumber: [[SECTION_OF_BEGIN=2]] + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/llvm/test/tools/llvm-readobj/COFF/pseudoreloc.test b/llvm/test/tools/llvm-readobj/COFF/pseudoreloc.test new file mode 100644 index 0000000000000..f9088b0e89b47 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/pseudoreloc.test @@ -0,0 +1,269 @@ +DEFINE: %{local1a_386} = 0x3000 +DEFINE: %{sym1_386} = 0x20B0 +DEFINE: %{sym3_386} = 0x20BC +DEFINE: %{local1a_x64} = 0x3000 +DEFINE: %{sym1_x64} = 0x20E8 +DEFINE: %{sym3_x64} = 0x20D8 + +RUN: yaml2obj -o %t.exe-x86_64 %p/Inputs/pseudoreloc.x86_64.yaml +RUN: llvm-readobj %t.exe-x86_64 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=CHECK,CHECK-X64 --match-full-lines --implicit-check-not=warning \ +RUN: -D#WORD=8 -D#SYM1=%{sym1_x64} -D#SYM3=%{sym3_x64} -D#LOCAL1A=%{local1a_x64} -DPREFIX= + +RUN: yaml2obj -o %t.exe-i386 %p/Inputs/pseudoreloc.i386.yaml +RUN: llvm-readobj %t.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=CHECK,CHECK-386 --match-full-lines --implicit-check-not=warning \ +RUN: -D#WORD=4 -D#SYM1=%{sym1_386} -D#SYM3=%{sym3_386} -D#LOCAL1A=%{local1a_386} -DPREFIX=_ + +CHECK-X64: Format: COFF-x86-64 +CHECK-X64-NEXT: Arch: x86_64 +CHECK-386: Format: COFF-i386 +CHECK-386-NEXT: Arch: i386 +CHECK-NEXT: AddressSize: [[#%u,BW:mul(WORD,8)]]bit +CHECK-NEXT: PseudoReloc [ +CHECK-NEXT: Entry { +CHECK-NEXT: Symbol: 0x[[#%X,SYM1]] +CHECK-NEXT: SymbolName: sym1 +CHECK-NEXT: Target: 0x[[#%X,LOCAL1A]] +CHECK-NEXT: TargetSymbol: .data+0x0 +CHECK-NEXT: BitWidth: [[#BW]] +CHECK-NEXT: } +CHECK-NEXT: Entry { +CHECK-NEXT: Symbol: 0x[[#%X,SYM1+mul(1,WORD)]] +CHECK-NEXT: SymbolName: sym2 +CHECK-NEXT: Target: 0x[[#%X,LOCAL1A+mul(1,WORD)]] +CHECK-NEXT: TargetSymbol: [[PREFIX]]local2a +CHECK-NEXT: BitWidth: [[#BW]] +CHECK-NEXT: } +CHECK-NEXT: Entry { +CHECK-NEXT: Symbol: 0x[[#%X,SYM3]] +CHECK-NEXT: SymbolName: sym3 +CHECK-NEXT: Target: 0x[[#%X,LOCAL1A+mul(2,WORD)]] +CHECK-NEXT: TargetSymbol: [[PREFIX]]local3a +CHECK-NEXT: BitWidth: [[#BW]] +CHECK-NEXT: } +CHECK-NEXT: Entry { +CHECK-NEXT: Symbol: 0x[[#%X,SYM3]] +CHECK-NEXT: SymbolName: sym3 +CHECK-NEXT: Target: 0x[[#%X,LOCAL1A+mul(3,WORD)]] +CHECK-NEXT: TargetSymbol: [[PREFIX]]local3a+0x[[#%X,mul(1,WORD)]] +CHECK-NEXT: BitWidth: [[#BW]] +CHECK-NEXT: } +CHECK-NEXT: Entry { +CHECK-NEXT: Symbol: 0x[[#%X,SYM1]] +CHECK-NEXT: SymbolName: sym1 +CHECK-NEXT: Target: 0x[[#%X,LOCAL1A+mul(4,WORD)]] +CHECK-NEXT: TargetSymbol: [[PREFIX]]local3a+0x[[#%X,mul(2,WORD)]] +CHECK-NEXT: BitWidth: [[#BW]] +CHECK-NEXT: } +CHECK-NEXT: ] + +; Test that llvm-readobj warns about missing imported symbol names. +RUN: yaml2obj -o %t.corrupted-iat.exe-i386 %p/Inputs/pseudoreloc.i386.yaml \ +RUN: -DSYMBOL0=30000000 -DSYMBOL1=B2200000 -DSYMBOL2=00FFFF00 +RUN: llvm-readobj %t.corrupted-iat.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefix=INVALIDSYMBOL --match-full-lines -D#LOCAL1A=%{local1a_386} --implicit-check-not=warning + +INVALIDSYMBOL: Symbol: 0x30 +INVALIDSYMBOL-NEXT: {{.*}}warning: {{.*}}: the reference of the symbol points out of the import table +INVALIDSYMBOL-NEXT: SymbolName: (missing) +INVALIDSYMBOL-NEXT: Target: 0x[[#%X,LOCAL1A]] +INVALIDSYMBOL: Symbol: 0x20B2 +INVALIDSYMBOL-NEXT: {{.*}}warning: {{.*}}: the reference of the symbol doesn't point imported symbol properly +INVALIDSYMBOL-NEXT: SymbolName: (missing) +INVALIDSYMBOL-NEXT: Target: 0x[[#%X,LOCAL1A+4]] +INVALIDSYMBOL: Symbol: 0xFFFF00 +INVALIDSYMBOL-NEXT: {{.*}}warning: {{.*}}: the reference of the symbol points out of the import table +INVALIDSYMBOL-NEXT: SymbolName: (missing) +INVALIDSYMBOL-NEXT: Target: 0x[[#%X,LOCAL1A+8]] + +; Assume the position of the section and the relocation list for further tests. +RUN: FileCheck --input-file=%p/Inputs/pseudoreloc.i386.yaml %s --check-prefix=RELOCPOS --match-full-lines + +RELOCPOS: sections: +RELOCPOS-NOT: - Name: +RELOCPOS: - Name: .text +RELOCPOS-NOT: - Name: +RELOCPOS: - Name: .rdata +RELOCPOS-NEXT: Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] +RELOCPOS-NEXT: VirtualAddress: 8192 +RELOCPOS: - Name: .data +RELOCPOS-NEXT: Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] +RELOCPOS-NEXT: VirtualAddress: 12288 +RELOCPOS: - Name: ___RUNTIME_PSEUDO_RELOC_LIST_END__ +RELOCPOS-NEXT: Value: {{\[\[END=80\]\]}} +RELOCPOS: - Name: ___RUNTIME_PSEUDO_RELOC_LIST__ +RELOCPOS-NEXT: Value: {{\[\[BEGIN=8\]\]}} +RELOCPOS-NEXT: SectionNumber: {{\[\[SECTION_OF_BEGIN=2\]\]}} + +; Test that llvm-readobj warns if a symbol belongs to a nonexistent section. +RUN: yaml2obj -o %t.nosection.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DSECTION_OF_LOCAL2A=999 +RUN: llvm-readobj %t.nosection.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=WARN-NOSECTION + +WARN-NOSECTION: section index out of bounds + +; Test that llvm-readobj shows an empty list if the relocation list has no contents. +RUN: yaml2obj -o %t.empty-list.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DEND=20 +RUN: llvm-readobj %t.empty-list.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=warning + +; Test that llvm-readobj shows an empty list if the relocation list has no header. +RUN: yaml2obj -o %t.no-header.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DEND=8 +RUN: llvm-readobj %t.no-header.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=warning + +; Test that llvm-readobj shows an empty list if the image is stripped. +RUN: llvm-readobj --coff-pseudoreloc %p/Inputs/imports.exe.coff-i386 2>&1 | \ +RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=warning + +; Test that llvm-readobj warns if the marker symbol of the relocation list is absent from the symbol table. +RUN: sed -e 's/__RUNTIME//' %p/Inputs/pseudoreloc.i386.yaml | \ +RUN: yaml2obj -o %t.nosymbol.exe-i386 +RUN: llvm-readobj %t.nosymbol.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=EMPTY,WARN-MISSINGMARKER + +; Test that llvm-readobj shows an empty list if a .obj is specified. +RUN: llvm-readobj --coff-pseudoreloc %p/Inputs/trivial.obj.coff-i386 2>&1 | \ +RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=warning + +; Test that llvm-readobj warns if the header of the relocation list is broken. +RUN: yaml2obj -o %t.broken-header.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DBEGIN=20 -DEND=48 +RUN: llvm-readobj %t.broken-header.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=EMPTY,WARN-INVALIDHEADER + +; Test that llvm-readobj warns if end < start. +RUN: yaml2obj -o %t.negative-size.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DBEGIN=20 -DEND=8 +RUN: llvm-readobj %t.negative-size.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=EMPTY,WARN-LOWEREND + +; Test that llvm-readobj warns if the marker symbol points out of the section space. +RUN: yaml2obj -o %t.outofrange-both.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DBEGIN=8888 -DEND=9999 +RUN: llvm-readobj %t.outofrange-both.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=EMPTY,WARN-OUTOFRANGE + +RUN: yaml2obj -o %t.outofrange-end.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DEND=9999 +RUN: llvm-readobj %t.outofrange-end.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=EMPTY,WARN-OUTOFRANGE + +; Test that llvm-readobj warns if the marker symbols point different sections. +RUN: yaml2obj -o %t.section-differs.exe-i386 %p/Inputs/pseudoreloc.i386.yaml -DSECTION_OF_BEGIN=1 +RUN: llvm-readobj %t.section-differs.exe-i386 --coff-pseudoreloc 2>&1 | \ +RUN: FileCheck %s --check-prefixes=EMPTY,WARN-SECTIONDIFFERS + +EMPTY: Format: COFF-i386 +EMPTY-NEXT: Arch: i386 +EMPTY-NEXT: AddressSize: 32bit +EMPTY-NEXT: PseudoReloc [ +WARN-MISSINGMARKER-NEXT: the marker symbols for runtime pseudo-relocation were not found +WARN-INVALIDHEADER-NEXT: invalid runtime pseudo-relocation records +WARN-LOWEREND-NEXT: the begin marker symbol for runtime pseudo-relocation must point to a lower address than where the end marker points +WARN-OUTOFRANGE-NEXT: the marker symbol of runtime pseudo-relocation points past the end of the section +WARN-SECTIONDIFFERS-NEXT: the marker symbols for runtime pseudo-relocation must point to the same section +EMPTY-NEXT: ] + +;; +;; To regenerate Inputs/pseudoreloc.*.yaml, run following one-liner and review actual address map: +;; +;; $ split-file pseudoreloc.test /tmp/pseudoreloc && bash /tmp/pseudoreloc/generate.sh && cp /tmp/pseudoreloc/*.yaml Inputs/ +;; + +#--- generate.sh +cd "$(dirname $0)" +set -e + +generate() { + LANG=C + local arch=$1 + local emul=$2 + + llc -mtriple $arch-mingw32 -filetype obj export1.ll -o export1.$arch.o + ld.lld -m $emul --dll export1.$arch.o -o export1.$arch.dll -entry= + llc -mtriple $arch-mingw32 -filetype obj export2.ll -o export2.$arch.o + ld.lld -m $emul --dll export2.$arch.o -o export2.$arch.dll -entry= + llc -mtriple $arch-mingw32 -filetype obj import.ll -o import.$arch.o + ld.lld -m $emul -S import.$arch.o export1.$arch.dll export2.$arch.dll -o pseudoreloc.$arch.exe -entry=start \ + --disable-dynamicbase --disable-reloc-section + + obj2yaml pseudoreloc.$arch.exe -o pseudoreloc.$arch.yaml.orig + + llvm-readobj --coff-imports --syms --section-headers pseudoreloc.$arch.exe > dump.$arch.txt + local begin=$(sed -n -e '/__RUNTIME_PSEUDO_RELOC_LIST__/,/Value:/{/Value:/{s/ *Value: *//p;q}}' dump.$arch.txt) + + # Make these parameterizable: + # - the referenced symbol in 1st, 2nd, and 3rd relocation entry + # - the marker symbols' value + # - a section which the marker symbol belongs to + # - a section which the symbol of the relocation target belongs to + sed -E -f - pseudoreloc.$arch.yaml.orig < pseudoreloc.$arch.yaml +/- Name: *\\.rdata/,/SectionData:/{ + s/( *SectionData: *[0-9A-F]{$(($begin * 2 + 24))})(.{8})(.{16})(.{8})(.{16})(.{8})/\\1[[SYMBOL0=\\2]]\\3[[SYMBOL1=\\4]]\\5[[SYMBOL2=\\6]]/ +} +/__RUNTIME_PSEUDO_RELOC_LIST_END__/,/Value:/{ + /Value:/s/([0-9]+)/[[END=\1]]/ +} +/__RUNTIME_PSEUDO_RELOC_LIST__/,/Value:/{ + /Value:/s/([0-9]+)/[[BEGIN=\1]]/ +} +/__RUNTIME_PSEUDO_RELOC_LIST__/,/SectionNumber:/{ + /SectionNumber:/s/([0-9]+)/[[SECTION_OF_BEGIN=\1]]/ +} +/local2a/,/SectionNumber:/{ + /SectionNumber:/s/([0-9]+)/[[SECTION_OF_LOCAL2A=\1]]/ +} +EOT + + # Ensure the binaries generated from the parameterized yaml and original one are exactly the same. + diff <(yaml2obj pseudoreloc.$arch.yaml.orig -o -) <(yaml2obj pseudoreloc.$arch.yaml -o -) +} + +generate i386 i386pe +generate x86_64 i386pep + +#--- export1.ll +@sym1 = dso_local dllexport global [4 x i8] c"\11\22\33\44" +@sym2 = dso_local dllexport global [4 x i8] c"\55\66\77\88" + +#--- export2.ll +@sym3 = dso_local dllexport global [4 x i8] c"\AA\BB\CC\DD" + +#--- import.ll +@__RUNTIME_PSEUDO_RELOC_LIST__ = external dso_local constant ptr +@__RUNTIME_PSEUDO_RELOC_LIST_END__ = external dso_local constant ptr +@sym1 = external dso_local global [4 x i8] +@sym2 = external dso_local global [4 x i8] +@sym3 = external dso_local global [4 x i8] +@dummy_to_bump_address = private constant i64 u0x4488226655117733 +@local1a = private global ptr getelementptr (i8, ptr @sym1, i32 1) +@local2a = dso_local global ptr getelementptr (i8, ptr @sym2, i32 2) +@local3a = dso_local global [2 x ptr] [ptr getelementptr (i8, ptr @sym3, i32 1), ptr getelementptr (i8, ptr @sym3, i32 1)] +@local1b = private global ptr getelementptr (i8, ptr @sym1, i32 2) + +define dso_local i32 @start() noinline nounwind { + %p1a = load ptr, ptr @local1a + %v1a = load i8, ptr %p1a + %x1a = sext i8 %v1a to i32 + %p2a = load ptr, ptr @local2a + %v2a = load i8, ptr %p2a + %x2a = sext i8 %v2a to i32 + %p3a = load ptr, ptr @local3a + %v3a = load i8, ptr %p3a + %x3a = sext i8 %v3a to i32 + %p1b = load ptr, ptr @local1b + %v1b = load i8, ptr %p1b + %x1b = sext i8 %v1b to i32 + %1 = add nsw i32 %x1a, %x2a + %2 = add nsw i32 %x3a, %x1b + %3 = add nsw i32 %1, %2 + ret i32 %3 +} + +define dso_local i32 @_pei386_runtime_relocator() noinline nounwind { + %1 = load ptr, ptr @__RUNTIME_PSEUDO_RELOC_LIST_END__ + %2 = load ptr, ptr @__RUNTIME_PSEUDO_RELOC_LIST__ + %3 = ptrtoint ptr %1 to i64 + %4 = ptrtoint ptr %2 to i64 + %5 = sub i64 %3, %4 + %6 = trunc i64 %5 to i32 + ret i32 %6 +} diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 96e0a634648e4..7c158bd1ab08e 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -95,6 +95,7 @@ class COFFDumper : public ObjDumper { void printCOFFExports() override; void printCOFFDirectives() override; void printCOFFBaseReloc() override; + void printCOFFPseudoReloc() override; void printCOFFDebugDirectory() override; void printCOFFTLSDirectory() override; void printCOFFResources() override; @@ -2000,6 +2001,267 @@ void COFFDumper::printCOFFBaseReloc() { } } +void COFFDumper::printCOFFPseudoReloc() { + ListScope D(W, "PseudoReloc"); + W.flush(); + + // Pseudo-relocations are only meaningful with PE image files. + if (!Obj->getDOSHeader()) + return; + + const StringRef RelocBeginName = Obj->getArch() == Triple::x86 + ? "___RUNTIME_PSEUDO_RELOC_LIST__" + : "__RUNTIME_PSEUDO_RELOC_LIST__"; + const StringRef RelocEndName = Obj->getArch() == Triple::x86 + ? "___RUNTIME_PSEUDO_RELOC_LIST_END__" + : "__RUNTIME_PSEUDO_RELOC_LIST_END__"; + + uint32_t Count = Obj->getNumberOfSymbols(); + // Skip if no symbol was found (maybe stripped). + if (Count == 0) + return; + + struct SymbolEntry { + uint32_t RVA; + COFFSymbolRef Symbol; + const coff_section *Section; + StringRef SymbolName; + }; + SmallVector RVASymbolMap; + COFFSymbolRef RelocBegin, RelocEnd; + for (uint32_t i = 0; i < Count; ++i) { + COFFSymbolRef Sym; + if (Expected SymOrErr = Obj->getSymbol(i)) { + Sym = *SymOrErr; + } else { + reportWarning(SymOrErr.takeError(), Obj->getFileName()); + continue; + } + + i += Sym.getNumberOfAuxSymbols(); + + if (Sym.getSectionNumber() <= 0) + continue; + + StringRef Name; + if (Expected NameOrErr = Obj->getSymbolName(Sym)) { + Name = *NameOrErr; + } else { + reportWarning(NameOrErr.takeError(), Obj->getFileName()); + continue; + } + + if (Name == RelocBeginName) + RelocBegin = Sym; + else if (Name == RelocEndName) + RelocEnd = Sym; + + const coff_section *Sec = nullptr; + if (Expected SecOrErr = + Obj->getSection(Sym.getSectionNumber())) { + Sec = *SecOrErr; + } else { + reportWarning(SecOrErr.takeError(), Obj->getFileName()); + continue; + } + + RVASymbolMap.push_back( + {Sec->VirtualAddress + Sym.getValue(), Sym, Sec, Name}); + } + + if (!RelocBegin.getRawPtr() || !RelocEnd.getRawPtr()) { + reportWarning( + createStringError( + "the marker symbols for runtime pseudo-relocation were not found"), + Obj->getFileName()); + return; + } + + const coff_section *Section = nullptr; + if (Expected SecOrErr = + Obj->getSection(RelocBegin.getSectionNumber())) { + Section = *SecOrErr; + } else { + reportWarning(SecOrErr.takeError(), Obj->getFileName()); + return; + } + + if (RelocBegin.getSectionNumber() != RelocEnd.getSectionNumber()) { + reportWarning(createStringError( + "the marker symbols for runtime pseudo-relocation must " + "point to the same section"), + Obj->getFileName()); + return; + } + + // Skip if the relocation list is empty. + if (RelocBegin.getValue() == RelocEnd.getValue()) + return; + + if (RelocEnd.getValue() < RelocBegin.getValue()) { + reportWarning( + createStringError( + "the begin marker symbol for runtime pseudo-relocation must point " + "to a lower address than where the end marker points"), + Obj->getFileName()); + return; + } + + ArrayRef Data; + if (auto E = Obj->getSectionContents(Section, Data)) { + reportWarning(std::move(E), Obj->getFileName()); + return; + } + + if (Data.size() <= RelocBegin.getValue() || + Data.size() <= RelocEnd.getValue()) { + reportWarning( + createStringError("the marker symbol of runtime pseudo-relocation " + "points past the end of the section"), + Obj->getFileName()); + return; + } + + ArrayRef RawRelocs = + Data.take_front(RelocEnd.getValue()).drop_front(RelocBegin.getValue()); + struct alignas(4) PseudoRelocationHeader { + PseudoRelocationHeader(uint32_t Signature) + : Zero1(0), Zero2(0), Signature(Signature) {} + support::ulittle32_t Zero1; + support::ulittle32_t Zero2; + support::ulittle32_t Signature; + }; + const PseudoRelocationHeader HeaderV2(1); + if (RawRelocs.size() < sizeof(HeaderV2) || + (memcmp(RawRelocs.data(), &HeaderV2, sizeof(HeaderV2)) != 0)) { + reportWarning( + createStringError("invalid runtime pseudo-relocation records"), + Obj->getFileName()); + return; + } + + struct alignas(4) PseudoRelocationRecord { + support::ulittle32_t Symbol; + support::ulittle32_t Target; + support::ulittle32_t BitSize; + }; + ArrayRef RelocRecords( + reinterpret_cast( + RawRelocs.data() + sizeof(PseudoRelocationHeader)), + (RawRelocs.size() - sizeof(PseudoRelocationHeader)) / + sizeof(PseudoRelocationRecord)); + + struct CachingImportedSymbolLookup { + struct SizedImportDirectoryEntry { + uint32_t StartRVA; + uint32_t EndRVA; + ImportDirectoryEntryRef EntryRef; + }; + + CachingImportedSymbolLookup(const COFFObjectFile *Obj) : Obj(Obj) { + for (auto D : Obj->import_directories()) { + auto &Entry = ImportDirectories.emplace_back(); + Entry.EntryRef = D; + Entry.EndRVA = 0; + if (auto E = D.getImportAddressTableRVA(Entry.StartRVA)) + reportError(std::move(E), Obj->getFileName()); + } + if (ImportDirectories.empty()) + return; + llvm::sort(ImportDirectories, [](const auto &x, const auto &y) { + return x.StartRVA < y.StartRVA; + }); + } + + Expected find(uint32_t EntryRVA) { + if (auto Ite = ImportedSymbols.find(EntryRVA); + Ite != ImportedSymbols.end()) + return Ite->second; + + auto Ite = llvm::upper_bound( + ImportDirectories, EntryRVA, + [](uint32_t RVA, const auto &D) { return RVA < D.StartRVA; }); + if (Ite == ImportDirectories.begin()) + return createStringError( + "the reference of the symbol points out of the import table"); + + --Ite; + uint32_t RVA = Ite->StartRVA; + if (Ite->EndRVA != 0 && Ite->EndRVA <= RVA) + return createStringError( + "the reference of the symbol points out of the import table"); + // Search with linear iteration to care if padding or garbage exist + // between ImportDirectoryEntry + for (auto S : Ite->EntryRef.imported_symbols()) { + if (RVA == EntryRVA) { + StringRef &NameDst = ImportedSymbols[RVA]; + if (auto E = S.getSymbolName(NameDst)) { + reportWarning(std::move(E), Obj->getFileName()); + NameDst = "(no symbol)"; + } + return NameDst; + } + RVA += Obj->is64() ? 8 : 4; + if (EntryRVA < RVA) + return createStringError("the reference of the symbol doesn't point " + "imported symbol properly"); + } + Ite->EndRVA = RVA; + + return createStringError( + "the reference of the symbol points out of the import table"); + } + + private: + const COFFObjectFile *Obj; + SmallVector ImportDirectories; + DenseMap ImportedSymbols; + }; + CachingImportedSymbolLookup ImportedSymbols(Obj); + llvm::stable_sort(RVASymbolMap, + [](const auto &x, const auto &y) { return x.RVA < y.RVA; }); + RVASymbolMap.erase( + llvm::unique(RVASymbolMap, + [](const auto &x, const auto &y) { return x.RVA == y.RVA; }), + RVASymbolMap.end()); + + for (const auto &Reloc : RelocRecords) { + DictScope Entry(W, "Entry"); + + W.printHex("Symbol", Reloc.Symbol); + if (Expected SymOrErr = ImportedSymbols.find(Reloc.Symbol)) { + W.printString("SymbolName", *SymOrErr); + } else { + reportWarning(SymOrErr.takeError(), Obj->getFileName()); + W.printString("SymbolName", "(missing)"); + } + + W.printHex("Target", Reloc.Target); + if (auto Ite = llvm::upper_bound( + RVASymbolMap, Reloc.Target.value(), + [](uint32_t RVA, const auto &Sym) { return RVA < Sym.RVA; }); + Ite == RVASymbolMap.begin()) { + W.printSymbolOffset("TargetSymbol", "(base)", Reloc.Target); + } else if (const uint32_t Offset = Reloc.Target.value() - (--Ite)->RVA; + Offset == 0) { + W.printString("TargetSymbol", Ite->SymbolName); + } else if (Offset < Ite->Section->VirtualSize) { + W.printSymbolOffset("TargetSymbol", Ite->SymbolName, Offset); + } else if (++Ite == RVASymbolMap.end()) { + W.printSymbolOffset("TargetSymbol", "(base)", Reloc.Target); + } else if (Expected NameOrErr = + Obj->getSectionName(Ite->Section)) { + W.printSymbolOffset("TargetSymbol", *NameOrErr, + Reloc.Target - Ite->Section->VirtualAddress); + } else { + reportWarning(NameOrErr.takeError(), Obj->getFileName()); + W.printSymbolOffset("TargetSymbol", "(base)", Reloc.Target); + } + + W.printNumber("BitWidth", Reloc.BitSize); + } +} + void COFFDumper::printCOFFResources() { ListScope ResourcesD(W, "Resources"); for (const SectionRef &S : Obj->sections()) { diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index 1dc29661f7178..a654078a770ff 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -146,6 +146,7 @@ class ObjDumper { virtual void printCOFFExports() { } virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } + virtual void printCOFFPseudoReloc() {} virtual void printCOFFDebugDirectory() { } virtual void printCOFFTLSDirectory() {} virtual void printCOFFResources() {} diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td index 48d43cc635a4f..711522c4acb14 100644 --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -87,6 +87,10 @@ def coff_directives : FF<"coff-directives", "Display .drectve section">, Group, Group; def coff_imports : FF<"coff-imports", "Display import table">, Group; def coff_load_config : FF<"coff-load-config", "Display load config">, Group; +def coff_pseudoreloc + : FF<"coff-pseudoreloc", + "Display runtime pseudo-relocations (Cygwin/MinGW specific)">, + Group; def coff_resources : FF<"coff-resources", "Display .rsrc section">, Group; def coff_tls_directory : FF<"coff-tls-directory", "Display TLS directory">, Group; diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 4c84ed701bb9a..2b34761b2cc6c 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -154,6 +154,7 @@ static bool CodeViewEnableGHash; static bool CodeViewMergedTypes; bool CodeViewSubsectionBytes; static bool COFFBaseRelocs; +static bool COFFPseudoRelocs; static bool COFFDebugDirectory; static bool COFFDirectives; static bool COFFExports; @@ -305,6 +306,7 @@ static void parseOptions(const opt::InputArgList &Args) { opts::CodeViewMergedTypes = Args.hasArg(OPT_codeview_merged_types); opts::CodeViewSubsectionBytes = Args.hasArg(OPT_codeview_subsection_bytes); opts::COFFBaseRelocs = Args.hasArg(OPT_coff_basereloc); + opts::COFFPseudoRelocs = Args.hasArg(OPT_coff_pseudoreloc); opts::COFFDebugDirectory = Args.hasArg(OPT_coff_debug_directory); opts::COFFDirectives = Args.hasArg(OPT_coff_directives); opts::COFFExports = Args.hasArg(OPT_coff_exports); @@ -492,6 +494,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, Dumper->printCOFFDirectives(); if (opts::COFFBaseRelocs) Dumper->printCOFFBaseReloc(); + if (opts::COFFPseudoRelocs) + Dumper->printCOFFPseudoReloc(); if (opts::COFFDebugDirectory) Dumper->printCOFFDebugDirectory(); if (opts::COFFTLSDirectory)