mirror of https://github.com/Shizmob/smol
epoch
This commit is contained in:
commit
6081557aa2
|
@ -0,0 +1,2 @@
|
|||
/bin
|
||||
/obj
|
|
@ -0,0 +1,44 @@
|
|||
LDRDIR = ldr
|
||||
OBJDIR = obj
|
||||
BINDIR = bin
|
||||
SRCDIR = src
|
||||
DATADIR = data
|
||||
|
||||
COPTFLAGS=-Os -fvisibility=hidden -mpreferred-stack-boundary=2 -fwhole-program \
|
||||
-ffast-math -funsafe-math-optimizations -fno-stack-protector -fomit-frame-pointer \
|
||||
-fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
|
||||
CXXOPTFLAGS=$(COPTFLAGS) \
|
||||
-fno-rtti -fno-enforce-eh-specs -fnothrow-opt -fno-use-cxa-get-exception-ptr \
|
||||
-fno-implicit-templates -fno-threadsafe-statics -fno-use-cxa-atexit
|
||||
|
||||
ASFLAGS=-f elf -I $(LDRDIR)/
|
||||
CFLAGS=-Wall -Wextra -Wpedantic -std=c99 $(COPTFLAGS) -nostartfiles -fno-PIC
|
||||
CXXFLAGS=-Wall -Wextra -Wpedantic -std=c++11 $(CXXOPTFLAGS) -nostartfiles -fno-PIC
|
||||
LIBS=-lGL -ldl -lc
|
||||
LDFLAGS=--oformat=binary -T ldr/link.ld
|
||||
|
||||
|
||||
.PHONY: all
|
||||
all: $(BINDIR)/test
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJDIR)/* $(BINDIR)/*
|
||||
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
$(OBJDIR)/%.o.syms: $(OBJDIR)/%.o
|
||||
readelf -s $^ | grep UND | sed 1d | awk '{ print $$8 }' > $@
|
||||
|
||||
$(OBJDIR)/symbols.%.s: $(OBJDIR)/%.o.syms
|
||||
$(LDRDIR)/mksyms $(LIBS) $$(cat $^) > $@
|
||||
|
||||
$(OBJDIR)/header.%.o: $(OBJDIR)/symbols.%.s $(LDRDIR)/header.s $(LDRDIR)/loader.s
|
||||
nasm $(ASFLAGS) $< -o $@
|
||||
|
||||
$(BINDIR)/%: $(OBJDIR)/%.o $(OBJDIR)/header.%.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
|
@ -0,0 +1,78 @@
|
|||
%define ORIGIN 0x400000
|
||||
|
||||
extern _size
|
||||
[section .header]
|
||||
|
||||
header:
|
||||
; e_ident
|
||||
db 0x7F, "ELF" ; EI_MAG0-EI_MAG3
|
||||
db 1 ; EI_CLASS: 1 = 32-bit
|
||||
db 1 ; EI_DATA: 1 = LSB
|
||||
db 1 ; EI_VERSION
|
||||
db 3 ; EI_OSABI: 3 = Linux
|
||||
db 1 ; EI_OSABIVERSION
|
||||
times 7 db 0 ; EI_PAD, ld.so is a busta and won't let us use our leet group tags for padding bytes :(
|
||||
; e_type: 2 = executable
|
||||
dw 2
|
||||
; e_machine: 3 = x86
|
||||
dw 3
|
||||
; e_version
|
||||
dd 1
|
||||
; e_entry
|
||||
dd _start
|
||||
; e_phoff
|
||||
dd (.segments - header)
|
||||
; e_shoff
|
||||
dd 0
|
||||
; e_flags
|
||||
dd 0
|
||||
; e_ehsize
|
||||
dw (.segments - header)
|
||||
; e_phentsize
|
||||
dw (.segments.load - .segments.dynamic)
|
||||
.segments:
|
||||
.segments.dynamic:
|
||||
; {e_phnum: 2, e_shentsize: 0}, p_type: 2 = PT_DYNAMIC
|
||||
dd 2
|
||||
; {e_shnum: <junk>, e_shstrnd: <junk>}, p_offset
|
||||
dd (.dynamic - header)
|
||||
; p_vaddr
|
||||
dd .dynamic
|
||||
; p_paddr
|
||||
dd 0
|
||||
; p_filesz
|
||||
dd (.dynamic.end - .dynamic)
|
||||
; p_memsz
|
||||
dd (.dynamic.end - .dynamic)
|
||||
; p_flags, p_align
|
||||
dq 0
|
||||
.segments.load:
|
||||
; p_type: 1 = PT_LOAD
|
||||
dd 1
|
||||
; p_offset
|
||||
dd 0
|
||||
; p_vaddr
|
||||
dd ORIGIN
|
||||
; p_paddr
|
||||
dd 0
|
||||
; p_filesz
|
||||
dd _size
|
||||
; p_memsz
|
||||
dd _size
|
||||
; p_flags: 1 = execute, 4 = read
|
||||
dd (1 | 2 | 4)
|
||||
; p_align
|
||||
dd 0x1000
|
||||
.segments.end:
|
||||
.dynamic:
|
||||
.dynamic.strtab:
|
||||
; d_tag: 5 = DT_STRTAB
|
||||
dd 5
|
||||
; d_un.d_ptr
|
||||
dd _symbols
|
||||
.dynamic.symtab:
|
||||
; this is required to be present or ld.so will crash, but it can be bogus
|
||||
; d_tag: 6 = DT_SYMTAB
|
||||
dd 6
|
||||
; d_un.d_ptr
|
||||
dd 0
|
|
@ -0,0 +1,24 @@
|
|||
OUTPUT_FORMAT(binary)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x400000;
|
||||
|
||||
.header : { *(.header) }
|
||||
|
||||
.text : {
|
||||
*(.text .text.* .rdata .rdata.* .rodata .rodata.*)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data .data.* .bss .bss.* .tdata .tdata.* .tbss .tbss.*)
|
||||
}
|
||||
|
||||
.dynamic : { *(.dynamic) } :all :dyn
|
||||
.dynstuff : { *(.symtab .strtab .shstrtab .rel.text .got.plt .gnu.linkonce.* .plt .plt.got .interp) } :all
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.*)
|
||||
}
|
||||
|
||||
_size = . - 0x400000;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
[section .text]
|
||||
|
||||
%define LM_NAME_OFFSET 0x4
|
||||
%define LM_NEXT_OFFSET 0xC
|
||||
%define LM_ADDR_OFFSET 0
|
||||
%define LM_INFO_OFFSET 0x20
|
||||
%define LM_NBUCKETS_OFFSET 0x178
|
||||
%define LM_GNU_BUCKETS_OFFSET 0x188
|
||||
%define LM_GNU_CHAIN_ZERO_OFFSET 0x18C
|
||||
|
||||
%define DT_VALUE_OFFSET 0x4
|
||||
%define DYN_PTR_OFFSET 0x4
|
||||
|
||||
%define DT_SYMTAB 0x6
|
||||
%define DT_SYMSIZE_SHIFT 4
|
||||
|
||||
|
||||
strcmp: ; (const char *s1 (esi), const char *s2 (edi))
|
||||
push esi
|
||||
push edi
|
||||
.cmp: lodsb
|
||||
or al, al
|
||||
jz .done
|
||||
sub al, [edi]
|
||||
jnz .done
|
||||
inc edi
|
||||
jmp .cmp
|
||||
.done: pop edi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
|
||||
basename: ; (const char *s (esi))
|
||||
push esi
|
||||
push edi
|
||||
mov edi, esi
|
||||
.cmp: lodsb
|
||||
or al, al
|
||||
jz .done
|
||||
cmp al, 47 ; '/'
|
||||
cmove edi, esi
|
||||
jmp .cmp
|
||||
.done: mov eax, edi
|
||||
pop edi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
|
||||
link_symbol: ; (struct link_map *entry, uint32_t *h)
|
||||
mov ecx, esi
|
||||
|
||||
; eax = *h % entry->l_nbuckets
|
||||
mov eax, [ecx]
|
||||
xor edx, edx
|
||||
mov ebx, [ebp + LM_NBUCKETS_OFFSET]
|
||||
div ebx
|
||||
; eax = entry->l_gnu_buckets[eax]
|
||||
mov eax, [ebp + LM_GNU_BUCKETS_OFFSET]
|
||||
mov eax, [eax + edx * 4]
|
||||
; *h |= 1
|
||||
or word [ecx], 1
|
||||
.check_bucket: ; edx = entry->l_gnu_chain_zero[eax] | 1
|
||||
mov edx, [ebp + LM_GNU_CHAIN_ZERO_OFFSET]
|
||||
mov edx, [edx + eax * 4]
|
||||
or edx, 1
|
||||
; check if this is our symbol
|
||||
cmp edx, [ecx]
|
||||
je .found
|
||||
inc eax
|
||||
jmp .check_bucket
|
||||
.found: ; it is! edx = entry->l_info[DT_SYMTAB]->d_un.d_ptr
|
||||
mov edx, [ebp + LM_INFO_OFFSET + DT_SYMTAB * 4]
|
||||
mov edx, [edx + DYN_PTR_OFFSET]
|
||||
; edx = edx[eax].dt_value + entry->l_addr
|
||||
shl eax, DT_SYMSIZE_SHIFT
|
||||
mov edx, [edx + eax + DT_VALUE_OFFSET]
|
||||
add edx, [ebp + LM_ADDR_OFFSET]
|
||||
sub edx, ecx
|
||||
sub edx, 4
|
||||
; finally, write it back!
|
||||
mov [ecx], edx
|
||||
ret
|
||||
|
||||
|
||||
link: ; (struct link_map *root, char *symtable)
|
||||
mov eax, [esp+4]
|
||||
mov esi, [esp+8]
|
||||
.do_library: ; null library name means end of symbol table, we're done
|
||||
cmp byte [esi], 0
|
||||
jz .done
|
||||
; setup start of map again
|
||||
mov ebp, eax
|
||||
push eax
|
||||
.find_map_entry: ; compare basename(entry->l_name) to lib name, if so we got a match
|
||||
push esi
|
||||
mov esi, [ebp + LM_NAME_OFFSET]
|
||||
call basename
|
||||
mov edi, eax
|
||||
pop esi
|
||||
call strcmp
|
||||
jz .process_map_entry
|
||||
; no match, next entry it is!
|
||||
mov ebp, [ebp + LM_NEXT_OFFSET]
|
||||
jmp .find_map_entry
|
||||
.process_map_entry: ; skip past the name in the symbol table now to get to the symbols
|
||||
lodsb
|
||||
or al, al
|
||||
jnz .process_map_entry
|
||||
|
||||
.do_symbols: ; null byte means end of symbols for this library!
|
||||
cmp byte [esi], 0
|
||||
jz .next_library
|
||||
inc esi
|
||||
call link_symbol
|
||||
add esi, 4
|
||||
jmp .do_symbols
|
||||
.next_library: pop eax
|
||||
inc esi
|
||||
jmp .do_library
|
||||
.done: ret
|
||||
|
||||
|
||||
extern main
|
||||
_start:
|
||||
push _symbols
|
||||
push eax
|
||||
call link
|
||||
|
||||
call main
|
||||
int3
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os.path
|
||||
import subprocess
|
||||
import itertools
|
||||
import argparse
|
||||
|
||||
|
||||
def hash_djb2(s):
|
||||
h = 5381
|
||||
for c in s:
|
||||
h = (h * 33 + ord(c)) & 0xFFFFFFFF
|
||||
return h
|
||||
|
||||
|
||||
def output_x86(libraries):
|
||||
shorts = { l: l.split('.', 1)[0].lower() for l in libraries }
|
||||
|
||||
print('%include "header.s"')
|
||||
print('.dynamic.needed:')
|
||||
for library in libraries:
|
||||
print('dd 1')
|
||||
print('dd (_symbols.{} - _symbols)'.format(shorts[library]))
|
||||
print('.dynamic.end:')
|
||||
print('_symbols:')
|
||||
for library, symbols in libraries.items():
|
||||
print('\t_symbols.{}: db "{}",0'.format(shorts[library], library))
|
||||
|
||||
for sym in symbols:
|
||||
hash = hash_djb2(sym)
|
||||
print("""
|
||||
\t\tglobal {name}
|
||||
\t\t{name}: db 0xE9
|
||||
\t\t dd 0x{hash:x}
|
||||
""".strip('\n').format(name=sym, hash=hash))
|
||||
|
||||
print('\tdb 0')
|
||||
print('db 0')
|
||||
print('%include "loader.s"')
|
||||
|
||||
|
||||
def get_cc_paths():
|
||||
output = subprocess.check_output(['cc', '-print-search-dirs'], stderr=subprocess.DEVNULL)
|
||||
paths = {}
|
||||
for entry in output.decode('utf-8').splitlines():
|
||||
category, path = entry.split(': ', 1)
|
||||
path = path.lstrip('=')
|
||||
paths[category] = list(set(os.path.realpath(p) for p in path.split(':') if os.path.isdir(p)))
|
||||
return paths
|
||||
|
||||
def find_symbol(paths, libraries, symbol):
|
||||
output = subprocess.check_output(['scanelf', '-B', '-F' '%s %S', '-s', '+{}'.format(symbol)] + paths, stderr=subprocess.DEVNULL)
|
||||
for entry in output.decode('utf-8').splitlines():
|
||||
sym, soname, path = entry.split(' ', 2)
|
||||
if symbol in sym.split(',') and any(soname.startswith(l) for l in libraries):
|
||||
return soname
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-a', '--architecture', default='x86', help='architecture to generate asm code for')
|
||||
parser.add_argument('-l', '--library', metavar='LIB', default=['c'], action='append', help='libraries to link against')
|
||||
parser.add_argument('symbols', metavar='SYM', nargs='+', help='symbol to search for')
|
||||
args = parser.parse_args()
|
||||
|
||||
paths = get_cc_paths()
|
||||
symbols = {}
|
||||
libraries = ['lib{}.so'.format(l) for l in args.library]
|
||||
|
||||
for symbol in args.symbols:
|
||||
library = find_symbol(paths['libraries'], libraries, symbol)
|
||||
if not library:
|
||||
sys.stderr.write('could not find symbol: {}\n'.format(symbol))
|
||||
sys.exit(1)
|
||||
symbols.setdefault(library, [])
|
||||
symbols[library].append(symbol)
|
||||
|
||||
output_x86(symbols)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,68 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
COPTFLAGS=$(cat <<'EOF'
|
||||
-Os -fvisibility=hidden -mpreferred-stack-boundary=2 -fwhole-program
|
||||
-ffast-math -funsafe-math-optimizations -fno-stack-protector -fomit-frame-pointer
|
||||
-fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
|
||||
EOF
|
||||
)
|
||||
CXXOPTFLAGS=$(cat <<EOF
|
||||
$CXXOPTFLAGS
|
||||
-fno-rtti -fno-enforce-eh-specs -fnothrow-opt -fno-use-cxa-get-exception-ptr
|
||||
-fno-implicit-templates -fno-threadsafe-statics -fno-use-cxa-atexit
|
||||
EOF
|
||||
)
|
||||
|
||||
CC="${CC:-cc}"
|
||||
CXX="${CXX:-c++}"
|
||||
CFLAGS="-Wall -Wextra -Wpedantic -std=c99 $COPTFLAGS -nostartfiles -fno-PIC"
|
||||
CXXFLAGS="-Wall -Wextra -Wpedantic -std=c++11 $CXXOPTFLAGS -nostartfiles -fno-PIC"
|
||||
ASFLAGS="-f elf -I ldr/"
|
||||
LDFLAGS="--oformat=binary -T ldr/link.ld"
|
||||
|
||||
mkdir -p bin
|
||||
rm -rf obj
|
||||
mkdir -p obj
|
||||
|
||||
cleared=
|
||||
mksym_args=
|
||||
files=
|
||||
symfiles=
|
||||
output=s.out
|
||||
i=1
|
||||
|
||||
add_out() {
|
||||
out="obj/$i"
|
||||
files="$files $out"
|
||||
i=$((i+1))
|
||||
}
|
||||
|
||||
add_syms() {
|
||||
readelf -s "$1" | grep UND | sed 1d | awk '{ print $8 }' > $1.syms
|
||||
symfiles="$symfiles $1.syms"
|
||||
}
|
||||
|
||||
for a; do
|
||||
if test -z "$cleared"; then
|
||||
set --; cleared=1
|
||||
fi
|
||||
case "$a" in
|
||||
-o) output="$a";;
|
||||
-l*) mksym_args="$mksym_args $a";;
|
||||
-*) set -- "$@" "$a";;
|
||||
*.c)
|
||||
add_out
|
||||
$CC $CFLAGS "$@" -c "$a" -o "$out"
|
||||
add_syms "$out";;
|
||||
*.cxx|*.cc|*.cpp)
|
||||
add_out
|
||||
$CXX $CXXFLAGS "$@" -c "$a" -o "$out"
|
||||
add_syms "$out";;
|
||||
*) printf "not sure what to do with input file: %s, bailing\n" "$a" &>2; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
./ldr/mksyms $mksym_args $(cat $symfiles) > obj/$output.syms.s
|
||||
nasm $ASFLAGS obj/$output.syms.s -o obj/$output.header.o
|
||||
ld $LDFLAGS obj/$output.header.o $files -o bin/$output
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const char *f = "foo";
|
||||
|
||||
int main(void) {
|
||||
printf("hello world %s\n", f);
|
||||
exit(42);
|
||||
}
|
Loading…
Reference in New Issue