add support for more than one relocation type on x86_64, make stack alignment optional

This commit is contained in:
PoroCYon 2019-02-05 17:07:18 +01:00 committed by PoroCYon
parent 560ce8c0f2
commit d9a5eac2e6
5 changed files with 69 additions and 14 deletions

View File

@ -8,7 +8,9 @@ PoC by Shiz, bugfixing and 64-bit version by PoroCYon.
```sh
./smol.py -lfoo -lbar input.o... smol-output.asm
nasm -I src/ [-DUSE_NX] [-DUSE_DL_FINI] -o nasm-output.o smol-output.asm
nasm -I src/ [-DUSE_INTERP] [-DALIGN_STACK] [-DUSE_NX] [-DUSE_DL_FINI] \
-o nasm-output.o smol-output.asm
# -DALIGN_STACK: 64-bit only.
ld -T ld/link.ld -o binary nasm-output.o input.o...
```

View File

@ -52,13 +52,13 @@ def main():
libs = list(find_libs(spaths, libnames))
symbols = {}
for symbol in syms:
for symbol, reloc in syms:
library = find_symbol(args.scanelf, libs, libnames, symbol)
if not library:
eprintf("could not find symbol: {}".format(symbol))
sys.exit(1)
symbols.setdefault(library, [])
symbols[library].append(symbol)
symbols[library].append((symbol, reloc))
output(arch, symbols, args.output)

View File

@ -15,11 +15,20 @@ def output_x86(libraries, outf):
outf.write('dd (_symbols.{} - _symbols)\n'.format(shorts[library]))
outf.write('.dynamic.end:\n')
# if needgot:
# outf.write('global _GLOBAL_OFFSET_TABLE_\n')
# outf.write('_GLOBAL_OFFSET_TABLE_:\n')
# outf.write('dd dynamic\n')
outf.write('_symbols:\n')
for library, symbols in libraries.items():
for library, symrels in libraries.items():
outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library))
for sym in symbols:
for sym, reloc in symrels:
# meh
if reloc != 'R_386_PC32':
eprintf('Relocation type ' + reloc + ' of symbol ' + sym + ' unsupported!')
sys.exit(1)
hash = hash_djb2(sym)
outf.write("""
\t\tglobal {name}
@ -46,11 +55,25 @@ def output_amd64(libraries, outf):
outf.write('dynamic.end:\n')
outf.write('[section .data.smolgot]\n')
# if needgot:
# outf.write('global _GLOBAL_OFFSET_TABLE_\n')
# outf.write('_GLOBAL_OFFSET_TABLE_:\n')
# outf.write('dq dynamic\n')
outf.write('_symbols:\n')
for library, symbols in libraries.items():
for library, symrels in libraries.items():
outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library))
for sym in symbols:
for sym, reloc in symrels:
if reloc != 'R_X86_64_PLT32' and reloc != 'R_X86_64_GOTPCRELX':
eprintf('Relocation type ' + reloc + ' of symbol ' + sym + ' unsupported!')
sys.exit(1)
if reloc == 'R_X86_64_GOTPCRELX':
outf.write("""
global {name}
{name}:
""".format(name=sym).lstrip('\n'))
hash = hash_djb2(sym)
outf.write('\t\t_symbols.{lib}.{name}: dq 0x{hash:x}\n'\
.format(lib=shorts[library],name=sym,hash=hash))
@ -60,9 +83,10 @@ def output_amd64(libraries, outf):
outf.write('_symbols.end:\n')
outf.write('_smolplt:\n')
for library, symbols in libraries.items():
for sym in symbols:
outf.write("""
for library, symrels in libraries.items():
for sym, reloc in symrels:
if reloc == 'R_X86_64_PLT32':
outf.write("""
[section .text.smolplt.{name}]
global {name}
{name}:

View File

@ -31,18 +31,45 @@ def decide_arch(inpfiles):
return archmagic[archn]
def build_reloc_typ_table(reo):
relocs = dict({})
for s in reo.decode('utf-8').splitlines():
stuff = s.split()
# prolly a 'header' line
if len(stuff) < 5:
continue
# yes, we're assuming every reference to the same symbol will use the
# same relocation type. if this isn't the case, your compiler flags are
# stupid
relocs[stuff[4]] = stuff[2]
return relocs
def get_needed_syms(readelf_bin, inpfiles):
output = subprocess.check_output([readelf_bin, '-s', '-W']+inpfiles,
stderr=subprocess.DEVNULL)
outrel = subprocess.check_output([readelf_bin, '-r', '-W']+inpfiles,
stderr=subprocess.DEVNULL)
relocs = build_reloc_typ_table(outrel)
syms=set({})
for entry in output.decode('utf-8').splitlines():
stuff = entry.split()
if len(stuff)<8: continue
if stuff[4] == "GLOBAL" and stuff[6] == "UND" and len(stuff[7])>0:
syms.add(stuff[7])
if stuff[4] == "GLOBAL" and stuff[6] == "UND" and len(stuff[7])>0 \
and stuff[7] in relocs:
syms.add((stuff[7], relocs[stuff[7]]))
return syms
#needgot = False
#if "_GLOBAL_OFFSET_TABLE_" in syms:
# needgot = True
# syms.remove("_GLOBAL_OFFSET_TABLE_")
return syms#, needgot
def get_cc_paths(cc_bin):
output = subprocess.check_output([cc_bin, '-print-search-dirs'],

View File

@ -44,7 +44,7 @@ _smol_start:
sub rsi, LF_ENTRY_OFF+8
xchg rbx, rsi
mov rsi, _symbols
mov esi, _symbols
; for (rsi = (uint8_t*)_symbols; *rsi; ++rsi) {
.next_needed:
@ -159,7 +159,9 @@ _smol_start:
.needed_end:
;xor rbp, rbp ; still 0 from _dl_start_user
mov rdi, rsp
%ifdef ALIGN_STACK
push rax
%endif
%ifdef USE_DL_FINI
xchg rsi, r13 ; _dl_fini
%endif