Skip to content

Instantly share code, notes, and snippets.

@jeremyd2019
Last active May 12, 2023 05:17
Show Gist options
  • Save jeremyd2019/cd388a0d7095b72b1f7266275d8d9001 to your computer and use it in GitHub Desktop.
Save jeremyd2019/cd388a0d7095b72b1f7266275d8d9001 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <gmp.h>
/* due to https://github.com/msys2/MINGW-packages/issues/15715
* variables/constants are lacking dllimport annotations. But clang/lld are
* doing some magic with refptrs that results in a simple access of gmp_version
* *not* requiring a pseudo-relocation. This more contrived example results in
* a pseudo-relocation on i386, x86_64, and aarch64, with gcc/bfd and clang/lld
* (as applicable) */
struct {
const char * const * ver;
} foo = {&gmp_version};
int main()
{
printf("%s\n", *foo.ver);
return 0;
}
#!/usr/bin/env python3
nm = 'x86_64-w64-mingw32-nm'
addr2line = 'x86_64-w64-mingw32-addr2line'
symbol_prefix = ''
import subprocess
import sys
import pefile
if len(sys.argv) <= 1:
print(sys.argv[0] + " exe")
sys.exit(0)
exe = sys.argv[1]
result = subprocess.run([nm, '-g', '--defined-only', exe], stdout=subprocess.PIPE)
symbols = {}
addresses = {}
for line in result.stdout.decode('utf-8').split('\n'):
cols = line.rstrip('\r').split(' ')
if len(cols) == 3:
sym = cols[2]
addr = cols[0]
symbols[sym] = addr
addr = addr.lstrip('0').lower()
if addr in addresses:
# Duplicate symbols pointing at the same address; prefer __imp_*
if sym.startswith('__imp'):
addresses[addr] = sym
else:
addresses[addr] = sym
pe = pefile.PE(exe, fast_load=True)
if pe.FILE_HEADER.Machine == pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_I386']:
symbol_prefix = '_'
start_sym_name = symbol_prefix + '__RUNTIME_PSEUDO_RELOC_LIST__'
end_sym_name = symbol_prefix + '__RUNTIME_PSEUDO_RELOC_LIST_END__'
if start_sym_name not in symbols or end_sym_name not in symbols:
print("No pseudo reloc symbols")
sys.exit(1)
base = pe.OPTIONAL_HEADER.ImageBase
pseudo_relocs_start = int(symbols[start_sym_name], 16) - base
pseudo_relocs_end = int(symbols[end_sym_name], 16) - base
# Assuming the modern v2 style pseudo reloc format; skip past 12 byte header.
pseudo_relocs_start = pseudo_relocs_start + 12
def resolve(exe, addr):
result = subprocess.run([addr2line, '-e', exe, addr], stdout=subprocess.PIPE)
lines = result.stdout.decode('utf-8').split('\n')
if len(lines) >= 1 and not '?' in lines[0]:
return lines[0].strip()
return None
if pseudo_relocs_start >= pseudo_relocs_end:
print("No pseudo relocs")
sys.exit(0)
pos = pseudo_relocs_start
while pos + 12 <= pseudo_relocs_end:
sym_addr = pe.get_dword_at_rva(pos) + base
sym_addr_str = "%x" % sym_addr
reloc_addr = pe.get_dword_at_rva(pos + 4) + base
reloc_addr_str = "%#x" % reloc_addr
size = pe.get_dword_at_rva(pos + 8) % 256
sym = sym_addr_str
if sym_addr_str in addresses:
sym = addresses[sym_addr_str]
loc = resolve(exe, reloc_addr_str)
if loc:
loc = ", referenced at " + loc
else:
loc = ""
print("Relocation at " + reloc_addr_str + " targeting " + sym + ", " + str(size) + " bits" + loc)
pos += 12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment