mirror of https://github.com/Shizmob/smol
64-bit version.
This commit is contained in:
parent
cccd9656de
commit
38ea8e9531
29
Makefile
29
Makefile
|
@ -4,6 +4,8 @@ SRCDIR := src
|
||||||
LDDIR := ld
|
LDDIR := ld
|
||||||
TESTDIR:= test
|
TESTDIR:= test
|
||||||
|
|
||||||
|
BITS ?= $(shell getconf LONG_BIT)
|
||||||
|
|
||||||
# -mpreferred-stack-boundary=3 messes up the stack and kills SSE!
|
# -mpreferred-stack-boundary=3 messes up the stack and kills SSE!
|
||||||
COPTFLAGS=-Os -fvisibility=hidden -fwhole-program \
|
COPTFLAGS=-Os -fvisibility=hidden -fwhole-program \
|
||||||
-ffast-math -funsafe-math-optimizations -fno-stack-protector -fomit-frame-pointer \
|
-ffast-math -funsafe-math-optimizations -fno-stack-protector -fomit-frame-pointer \
|
||||||
|
@ -15,12 +17,18 @@ CXXOPTFLAGS=$(COPTFLAGS) \
|
||||||
CFLAGS=-Wall -Wextra -Wpedantic -std=gnu11 -nostartfiles -fno-PIC $(COPTFLAGS)
|
CFLAGS=-Wall -Wextra -Wpedantic -std=gnu11 -nostartfiles -fno-PIC $(COPTFLAGS)
|
||||||
CXXFLAGS=-Wall -Wextra -Wpedantic -std=c++11 $(CXXOPTFLAGS) -nostartfiles -fno-PIC
|
CXXFLAGS=-Wall -Wextra -Wpedantic -std=c++11 $(CXXOPTFLAGS) -nostartfiles -fno-PIC
|
||||||
|
|
||||||
ASFLAGS=-f elf -I $(SRCDIR)/
|
ASFLAGS=-I $(SRCDIR)/
|
||||||
|
ifeq ($(BITS),32)
|
||||||
LDFLAGS=-m elf_i386
|
LDFLAGS=-m elf_i386
|
||||||
|
ASFLAGS += -f elf32
|
||||||
|
else
|
||||||
|
LDFLAGS=-m elf_x86_64
|
||||||
|
ASFLAGS += -f elf64
|
||||||
|
endif
|
||||||
LDFLAGS_=$(LDFLAGS) -T $(LDDIR)/link.ld --oformat=binary
|
LDFLAGS_=$(LDFLAGS) -T $(LDDIR)/link.ld --oformat=binary
|
||||||
|
|
||||||
CFLAGS += -m32
|
CFLAGS += -m$(BITS)
|
||||||
CXXFLAGS += -m32
|
CXXFLAGS += -m$(BITS)
|
||||||
|
|
||||||
LIBS=-lc
|
LIBS=-lc
|
||||||
|
|
||||||
|
@ -29,7 +37,7 @@ ASFLAGS += -DUSE_INTERP
|
||||||
NASM ?= nasm
|
NASM ?= nasm
|
||||||
PYTHON3 ?= python3
|
PYTHON3 ?= python3
|
||||||
|
|
||||||
all: $(BINDIR)/sdl $(BINDIR)/hello
|
all: $(BINDIR)/hello $(BINDIR)/sdl
|
||||||
|
|
||||||
LIBS += -lSDL2 -lGL
|
LIBS += -lSDL2 -lGL
|
||||||
|
|
||||||
|
@ -42,25 +50,22 @@ clean:
|
||||||
.SECONDARY:
|
.SECONDARY:
|
||||||
|
|
||||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(OBJDIR)/
|
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(OBJDIR)/
|
||||||
$(CC) -m32 $(CFLAGS) -c "$<" -o "$@"
|
$(CC) $(CFLAGS) -c "$<" -o "$@"
|
||||||
$(OBJDIR)/%.o: $(TESTDIR)/%.c $(OBJDIR)/
|
$(OBJDIR)/%.o: $(TESTDIR)/%.c $(OBJDIR)/
|
||||||
$(CC) -m32 $(CFLAGS) -c "$<" -o "$@"
|
$(CC) $(CFLAGS) -c "$<" -o "$@"
|
||||||
|
|
||||||
$(OBJDIR)/%.start.o: $(OBJDIR)/%.o $(OBJDIR)/crt1.o
|
$(OBJDIR)/%.start.o: $(OBJDIR)/%.o $(OBJDIR)/crt1.o
|
||||||
$(LD) $(LDFLAGS) -r -o "$@" $^
|
$(LD) $(LDFLAGS) -r -o "$@" $^
|
||||||
|
|
||||||
$(OBJDIR)/crt1.o: $(SRCDIR)/crt1.c $(OBJDIR)/
|
|
||||||
$(CC) $(CFLAGS) -c "$<" -o "$@"
|
|
||||||
|
|
||||||
$(OBJDIR)/symbols.%.asm: $(OBJDIR)/%.start.o
|
$(OBJDIR)/symbols.%.asm: $(OBJDIR)/%.start.o
|
||||||
$(PYTHON3) ./smol.py $(LIBS) "$<" "$@"
|
$(PYTHON3) ./smol.py $(LIBS) "$<" "$@"
|
||||||
|
|
||||||
$(OBJDIR)/stub.%.o: $(OBJDIR)/symbols.%.asm $(SRCDIR)/header.asm \
|
$(OBJDIR)/stub.%.o: $(OBJDIR)/symbols.%.asm $(SRCDIR)/header32.asm \
|
||||||
$(SRCDIR)/loader.asm
|
$(SRCDIR)/loader32.asm
|
||||||
$(NASM) $(ASFLAGS) $< -o $@
|
$(NASM) $(ASFLAGS) $< -o $@
|
||||||
|
|
||||||
$(BINDIR)/%: $(OBJDIR)/%.start.o $(OBJDIR)/stub.%.o $(BINDIR)/
|
$(BINDIR)/%: $(OBJDIR)/%.start.o $(OBJDIR)/stub.%.o $(BINDIR)/
|
||||||
$(LD) $(LDFLAGS_) $(OBJDIR)/$*.start.o $(OBJDIR)/stub.$*.o -o "$@"
|
$(LD) -Map=$(BINDIR)/$*.map $(LDFLAGS_) $(OBJDIR)/$*.start.o $(OBJDIR)/stub.$*.o -o "$@"
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
|
|
29
ld/link.ld
29
ld/link.ld
|
@ -2,25 +2,50 @@ OUTPUT_FORMAT(binary)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 0x400000;
|
. = 0x400000;
|
||||||
|
_smol_origin = .;
|
||||||
|
|
||||||
.header : { *(.header) }
|
.header : { *(.header) }
|
||||||
|
|
||||||
|
_smol_text_start = .;
|
||||||
|
_smol_text_off = _smol_text_start - _smol_origin;
|
||||||
.text : {
|
.text : {
|
||||||
*(.text.startup.smol)
|
*(.text.startup.smol)
|
||||||
*(.text.startup._start)
|
*(.text.startup._start)
|
||||||
*(.text .text.* .rdata .rdata.* .rodata .rodata.*)
|
*(.text .text.* .rdata .rdata.* .rodata .rodata.*)
|
||||||
}
|
}
|
||||||
|
_smol_text_end = .;
|
||||||
|
_smol_text_size = _smol_text_end - _smol_text_start;
|
||||||
|
|
||||||
|
_smol_textandheader_size = _smol_text_end - _smol_origin;
|
||||||
|
|
||||||
|
_smol_data_start = .;
|
||||||
|
_smol_data_off = _smol_data_start - _smol_origin;
|
||||||
.data : {
|
.data : {
|
||||||
*(.data .data.* .tdata .tdata.* .bss .bss.* .tbss .tbss.*)
|
*(.data.smolgot)
|
||||||
|
*(.data .data.* .tdata .tdata.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
.dynamic : { *(.dynamic) } :all :dyn
|
.dynamic : { *(.dynamic) } :all :dyn
|
||||||
.dynstuff : { *(.symtab .strtab .shstrtab .rel.text .got.plt .gnu.linkonce.* .plt .plt.got .interp) } :all
|
.dynstuff : { *(.symtab .strtab .shstrtab .rel.text .got.plt .gnu.linkonce.* .plt .plt.got .interp) } :all
|
||||||
|
_smol_data_end = .;
|
||||||
|
_smol_data_size = _smol_data_end - _smol_data_start;
|
||||||
|
|
||||||
|
_smol_total_filesize = . - _smol_origin;
|
||||||
|
|
||||||
|
_smol_bss_start = .;
|
||||||
|
_smol_bss_off = _smol_bss_start - _smol_origin;
|
||||||
|
.bss : {
|
||||||
|
*(.bss .bss.* .tbss .tbss.* .sbss .sbss.*)
|
||||||
|
}
|
||||||
|
_smol_bss_end = .;
|
||||||
|
_smol_bss_size = _smol_bss_end - _smol_bss_start;
|
||||||
|
|
||||||
|
_smol_dataandbss_size = _smol_bss_end - _smol_data_start;
|
||||||
|
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.*)
|
*(.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
_smol_total_size = . - 0x400000;
|
_smol_total_memsize = . - _smol_origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
54
smolemit.py
54
smolemit.py
|
@ -11,14 +11,16 @@ def hash_djb2(s):
|
||||||
|
|
||||||
def output_x86(libraries, outf):
|
def output_x86(libraries, outf):
|
||||||
outf.write('; vim: set ft=nasm:\n') # be friendly
|
outf.write('; vim: set ft=nasm:\n') # be friendly
|
||||||
|
outf.write('bits 32\n')
|
||||||
shorts = { l: l.split('.', 1)[0].lower().replace('-', '_') for l in libraries }
|
shorts = { l: l.split('.', 1)[0].lower().replace('-', '_') for l in libraries }
|
||||||
|
|
||||||
outf.write('%include "header.asm"\n')
|
outf.write('%include "header32.asm"\n')
|
||||||
outf.write('.dynamic.needed:\n')
|
outf.write('.dynamic.needed:\n')
|
||||||
for library in libraries:
|
for library in libraries:
|
||||||
outf.write('dd 1\n')
|
outf.write('dd 1;DT_NEEDED\n')
|
||||||
outf.write('dd (_symbols.{} - _symbols)\n'.format(shorts[library]))
|
outf.write('dd (_symbols.{} - _symbols)\n'.format(shorts[library]))
|
||||||
outf.write('.dynamic.end:\n')
|
outf.write('.dynamic.end:\n')
|
||||||
|
|
||||||
outf.write('_symbols:\n')
|
outf.write('_symbols:\n')
|
||||||
for library, symbols in libraries.items():
|
for library, symbols in libraries.items():
|
||||||
outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library))
|
outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library))
|
||||||
|
@ -31,15 +33,53 @@ def output_x86(libraries, outf):
|
||||||
\t\t dd 0x{hash:x}
|
\t\t dd 0x{hash:x}
|
||||||
""".format(name=sym, hash=hash).lstrip('\n'))
|
""".format(name=sym, hash=hash).lstrip('\n'))
|
||||||
|
|
||||||
outf.write('\tdb 0\n')
|
outf.write('\tdb 0\n') # TODO: not a dd?
|
||||||
outf.write('db 0\n')
|
outf.write('db 0\n')
|
||||||
outf.write('%include "loader.asm"\n')
|
outf.write('_symbols.end:\n')
|
||||||
|
|
||||||
|
outf.write('%include "loader32.asm"\n')
|
||||||
|
|
||||||
|
def output_amd64(libraries, outf):
|
||||||
|
outf.write('; vim: set ft=nasm:\n')
|
||||||
|
outf.write('bits 64\n')
|
||||||
|
shorts = { l: l.split('.', 1)[0].lower().replace('-', '_') for l in libraries }
|
||||||
|
|
||||||
|
outf.write('%include "header64.asm"\n')
|
||||||
|
outf.write('dynamic.needed:\n')
|
||||||
|
for library in libraries:
|
||||||
|
outf.write('dq 1;DT_NEEDED\n')
|
||||||
|
outf.write('dq (_symbols.{} - _symbols)\n'.format(shorts[library]))
|
||||||
|
outf.write('dynamic.end:\n')
|
||||||
|
|
||||||
|
outf.write('[section .data.smolgot]\n')
|
||||||
|
outf.write('_symbols:\n')
|
||||||
|
for library, symbols in libraries.items():
|
||||||
|
outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library))
|
||||||
|
|
||||||
|
for sym in symbols:
|
||||||
|
hash = hash_djb2(sym)
|
||||||
|
outf.write('\t\t_symbols.{lib}.{name}: dq 0x{hash:x}\n'\
|
||||||
|
.format(lib=shorts[library],name=sym,hash=hash))
|
||||||
|
|
||||||
|
outf.write('\tdq 0\n')
|
||||||
|
outf.write('db 0\n')
|
||||||
|
outf.write('_symbols.end:\n')
|
||||||
|
|
||||||
|
outf.write('_smolplt:\n')
|
||||||
|
for library, symbols in libraries.items():
|
||||||
|
for sym in symbols:
|
||||||
|
outf.write("""
|
||||||
|
[section .text.smolplt.{name}]
|
||||||
|
global {name}
|
||||||
|
{name}:
|
||||||
|
jmp [rel _symbols.{lib}.{name}]
|
||||||
|
""".format(lib=shorts[library],name=sym).lstrip('\n'))
|
||||||
|
|
||||||
|
outf.write('_smolplt.end:\n')
|
||||||
|
outf.write('%include "loader64.asm"\n')
|
||||||
def output(arch, libraries, outf):
|
def output(arch, libraries, outf):
|
||||||
if arch == 'i386': output_x86(libraries, outf)
|
if arch == 'i386': output_x86(libraries, outf)
|
||||||
##elif arch == 'arm':
|
elif arch == 'x86_64': output_amd64(libraries, outf)
|
||||||
#elif arch == 'x86_64':
|
|
||||||
###elif arch == 'aarch64':
|
|
||||||
else:
|
else:
|
||||||
eprintf("E: cannot emit for arch '" + str(arch) + "'")
|
eprintf("E: cannot emit for arch '" + str(arch) + "'")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
archmagic = {
|
archmagic = {
|
||||||
'i386': 3, 3: 'i386',
|
'i386': 3, 3: 'i386' ,
|
||||||
##'arm': 40, 40: 'arm',
|
'x86_64': 62, 62: 'x86_64',
|
||||||
#'x86_64': 62, 62: 'x86_64',
|
|
||||||
###'aarch64': 183, 183: 'aarch64'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def eprintf(*args, **kwargs): print(*args, file=sys.stderr, **kwargs)
|
def eprintf(*args, **kwargs): print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
|
@ -8,10 +8,12 @@ extern int __libc_start_main(int (*main)(int, char**),
|
||||||
void (*rtld_fini)(void),
|
void (*rtld_fini)(void),
|
||||||
void* stack) __attribute__((__noreturn__));
|
void* stack) __attribute__((__noreturn__));
|
||||||
|
|
||||||
__attribute__((__externally_visible__, __section__(".text.startup._start"), __noreturn__))
|
__attribute__((__externally_visible__, __section__(".text.startup._start"),
|
||||||
|
__noreturn__))
|
||||||
int _start(void* stack) {
|
int _start(void* stack) {
|
||||||
int argc=*(int*)stack;
|
// TODO: _dl_fini etc.
|
||||||
char** argv=(void*)(&((int*)stack)[1]);
|
int argc=*(size_t*)stack;
|
||||||
|
char** argv=(void*)(&((size_t*)stack)[1]);
|
||||||
|
|
||||||
__libc_start_main(main, argc, argv, NULL, NULL, NULL, (void*)stack);
|
__libc_start_main(main, argc, argv, NULL, NULL, NULL, (void*)stack);
|
||||||
|
|
||||||
|
|
10
src/elf.inc
10
src/elf.inc
|
@ -1,6 +1,10 @@
|
||||||
; vim: set ft=nasm:
|
; vim: set ft=nasm:
|
||||||
|
|
||||||
|
%if __BITS__ == 32
|
||||||
%define EI_CLASS (1) ; 1 == 32-bit
|
%define EI_CLASS (1) ; 1 == 32-bit
|
||||||
|
%else
|
||||||
|
%define EI_CLASS (2) ; 2 == 64-bit
|
||||||
|
%endif
|
||||||
%define EI_DATA (1) ; 1 == little-endian
|
%define EI_DATA (1) ; 1 == little-endian
|
||||||
%define EI_VERSION (1) ; current
|
%define EI_VERSION (1) ; current
|
||||||
%define EI_OSABI (3) ; Linux
|
%define EI_OSABI (3) ; Linux
|
||||||
|
@ -9,7 +13,11 @@
|
||||||
%define ELF_TYPE (2) ; 2 == executable
|
%define ELF_TYPE (2) ; 2 == executable
|
||||||
|
|
||||||
%ifndef ELF_MACHINE
|
%ifndef ELF_MACHINE
|
||||||
%define ELF_MACHINE (3) ; 3 == i386
|
%if __BITS__ == 32
|
||||||
|
%define ELF_MACHINE ( 3) ; 3 == i386
|
||||||
|
%else
|
||||||
|
%define ELF_MACHINE (62) ; 62 == x86_64
|
||||||
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%define PT_LOAD (1)
|
%define PT_LOAD (1)
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
; vim: set ft=nasm:
|
; vim: set ft=nasm:
|
||||||
|
|
||||||
%define ORIGIN 0x400000
|
%include "linkscr.inc"
|
||||||
;org ORIGIN
|
|
||||||
bits 32
|
|
||||||
|
|
||||||
extern _smol_total_size
|
|
||||||
[section .header]
|
[section .header]
|
||||||
|
|
||||||
%include "elf.inc"
|
%include "elf.inc"
|
||||||
|
@ -25,7 +22,33 @@ header:
|
||||||
dd 0 ; e_flags
|
dd 0 ; e_flags
|
||||||
dw (.segments - header) ; e_ehsize
|
dw (.segments - header) ; e_ehsize
|
||||||
dw (.segments.load - .segments.dynamic) ; e_phentsize
|
dw (.segments.load - .segments.dynamic) ; e_phentsize
|
||||||
|
%ifdef USE_NX
|
||||||
|
%error "USE_NX not supported yet on i386 ('GOT' still needs RWX, and alignment has to be fixed)"
|
||||||
|
;%ifdef USE_INTERP
|
||||||
|
; dw 4, 0 ; e_phnum, e_shentsize
|
||||||
|
;%else
|
||||||
|
; dw 3, 0
|
||||||
|
;%endif
|
||||||
|
;.segments:
|
||||||
|
;.segments.load.text:
|
||||||
|
; dd PT_LOAD
|
||||||
|
; dd _smol_origin
|
||||||
|
; dd _smol_text_start, 0
|
||||||
|
; dd _smol_textandheader_size
|
||||||
|
; dd _smol_textandheader_size
|
||||||
|
; dd (PHDR_R | PHDR_X)
|
||||||
|
; dd 0x1000
|
||||||
|
;.segments.load.data:
|
||||||
|
; dd PT_LOAD
|
||||||
|
; dd _smol_data_off
|
||||||
|
; dd _smol_data_start, 0
|
||||||
|
; dd _smol_data_size
|
||||||
|
; dd _smol_dataandbss_size
|
||||||
|
; dd (PHDR_R | PHDR_W)
|
||||||
|
; dd 0x1;000
|
||||||
|
%else
|
||||||
.segments:
|
.segments:
|
||||||
|
%endif
|
||||||
%ifdef USE_INTERP
|
%ifdef USE_INTERP
|
||||||
.segments.interp:
|
.segments.interp:
|
||||||
dd PT_INTERP ; {e_phnum: 2, e_shentsize: 0}, p_type
|
dd PT_INTERP ; {e_phnum: 2, e_shentsize: 0}, p_type
|
||||||
|
@ -42,14 +65,17 @@ header:
|
||||||
dd (.dynamic.end - .dynamic) ; p_filesz
|
dd (.dynamic.end - .dynamic) ; p_filesz
|
||||||
dd (.dynamic.end - .dynamic) ; p_memsz
|
dd (.dynamic.end - .dynamic) ; p_memsz
|
||||||
dd 0, 0 ; p_flags, p_align
|
dd 0, 0 ; p_flags, p_align
|
||||||
|
%ifndef USE_NX
|
||||||
.segments.load:
|
.segments.load:
|
||||||
dd PT_LOAD ; p_type: 1 = PT_LOAD
|
dd PT_LOAD ; p_type: 1 = PT_LOAD
|
||||||
dd 0 ; p_offset
|
dd 0 ; p_offset
|
||||||
dd ORIGIN, 0 ; p_vaddr, p_paddr
|
dd _smol_origin, 0 ; p_vaddr, p_paddr
|
||||||
dd _smol_total_size ; p_filesz
|
; use memsize twice here, linux doesn't care and it compresses better
|
||||||
dd _smol_total_size ; p_memsz
|
dd _smol_total_memsize ; p_filesz
|
||||||
|
dd _smol_total_memsize ; p_memsz
|
||||||
dd (PHDR_R | PHDR_W | PHDR_X) ; p_flags
|
dd (PHDR_R | PHDR_W | PHDR_X) ; p_flags
|
||||||
dd 0x1000 ; p_align
|
dd 0x1000 ; p_align
|
||||||
|
%endif
|
||||||
.segments.end:
|
.segments.end:
|
||||||
%ifdef USE_INTERP
|
%ifdef USE_INTERP
|
||||||
.interp:
|
.interp:
|
|
@ -0,0 +1,84 @@
|
||||||
|
; vim: set ft=nasm:
|
||||||
|
|
||||||
|
%include "linkscr.inc"
|
||||||
|
|
||||||
|
[section .header]
|
||||||
|
|
||||||
|
%include "elf.inc"
|
||||||
|
|
||||||
|
ehdr:
|
||||||
|
; e_ident
|
||||||
|
db 0x7F, "ELF"
|
||||||
|
db EI_CLASS, EI_DATA, EI_VERSION, EI_OSABI
|
||||||
|
db EI_OSABIVERSION
|
||||||
|
times 7 db 0
|
||||||
|
dw ELF_TYPE ; e_type
|
||||||
|
dw ELF_MACHINE ; e_machine
|
||||||
|
dd EI_VERSION ; e_version
|
||||||
|
dq _smol_start ; e_entry
|
||||||
|
dq phdr - ehdr ; e_phoff
|
||||||
|
dq 0 ; e_shoff
|
||||||
|
dd 0 ; e_flags
|
||||||
|
dw ehdr.end - ehdr ; e_ehsize
|
||||||
|
dw phdr.load - phdr.dynamic ; e_phentsize
|
||||||
|
|
||||||
|
%ifdef USE_NX
|
||||||
|
%ifdef USE_INTERP
|
||||||
|
dw 4 ; e_phnum
|
||||||
|
%else
|
||||||
|
dw 3 ; e_phnum
|
||||||
|
%endif
|
||||||
|
dw 0, 0, 0 ; e_shentsize, e_shnum, e_shstrndx
|
||||||
|
%else
|
||||||
|
phdr:
|
||||||
|
%ifdef USE_INTERP
|
||||||
|
phdr.interp:
|
||||||
|
dd PT_INTERP ; p_type ; e_phnum, e_shentsize
|
||||||
|
dd 0 ; p_flags ; e_shnum, e_shstrndx
|
||||||
|
ehdr.end:
|
||||||
|
dq interp - ehdr ; p_offset
|
||||||
|
dq interp, interp ; p_vaddr, p_paddr
|
||||||
|
dq interp.end - interp ; p_filesz
|
||||||
|
dq interp.end - interp ; p_memsz
|
||||||
|
dq 0 ; p_align
|
||||||
|
%endif
|
||||||
|
phdr.dynamic:
|
||||||
|
dd PT_DYNAMIC ; p_type ; e_phnum, e_shentsize
|
||||||
|
dd 0 ; p_flags ; e_shnum, e_shstrndx
|
||||||
|
%ifndef USE_INTERP
|
||||||
|
ehdr.end:
|
||||||
|
%endif
|
||||||
|
dq dynamic - ehdr ; p_offset
|
||||||
|
dq dynamic, 0 ; p_vaddr, p_paddr
|
||||||
|
dq dynamic.end - dynamic ; p_filesz
|
||||||
|
dq dynamic.end - dynamic ; p_memsz
|
||||||
|
dq 0 ; p_align
|
||||||
|
%ifndef USE_NX
|
||||||
|
phdr.load:
|
||||||
|
dd PT_LOAD ; p_type
|
||||||
|
dd PHDR_R | PHDR_W | PHDR_X ; p_flags
|
||||||
|
dq 0 ; p_offset
|
||||||
|
dq ehdr, 0 ; p_vaddr, p_paddr
|
||||||
|
dq _smol_total_memsize ; p_filesz
|
||||||
|
dq _smol_total_memsize ; p_memsz
|
||||||
|
dq 0x1000 ; p_align
|
||||||
|
%else
|
||||||
|
%error "TODO" ; TODO
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifdef USE_INTERP
|
||||||
|
interp:
|
||||||
|
db "/lib64/ld-linux-x86-64.so.2", 0
|
||||||
|
interp.end:
|
||||||
|
%endif
|
||||||
|
|
||||||
|
dynamic:
|
||||||
|
dynamic.strtab:
|
||||||
|
dq DT_STRTAB ; d_tag
|
||||||
|
dq _symbols ; d_un.d_ptr
|
||||||
|
dynamic.symtab:
|
||||||
|
dq DT_SYMTAB ; d_tag
|
||||||
|
dq 0 ; d_un.d_ptr
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
; vim: set ft=nasm:
|
||||||
|
|
||||||
|
extern _smol_origin
|
||||||
|
extern _smol_total_size
|
||||||
|
extern _smol_text_start
|
||||||
|
extern _smol_text_off
|
||||||
|
extern _smol_text_end
|
||||||
|
extern _smol_text_size
|
||||||
|
extern _smol_textandheader_size
|
||||||
|
extern _smol_data_start
|
||||||
|
extern _smol_data_off
|
||||||
|
extern _smol_data_end
|
||||||
|
extern _smol_data_size
|
||||||
|
extern _smol_total_filesize
|
||||||
|
extern _smol_bss_start
|
||||||
|
extern _smol_bss_off
|
||||||
|
extern _smol_bss_end
|
||||||
|
extern _smol_bss_size
|
||||||
|
extern _smol_dataandbss_size
|
||||||
|
extern _smol_total_memsize
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
_smol_start:
|
_smol_start:
|
||||||
|
push edx ; _dl_fini
|
||||||
; try to get the 'version-agnostic' pffset of the stuff we're
|
; try to get the 'version-agnostic' pffset of the stuff we're
|
||||||
; interested in
|
; interested in
|
||||||
mov ebx, eax
|
mov ebx, eax
|
||||||
|
@ -15,7 +16,7 @@ _smol_start:
|
||||||
cmp dword eax, _smol_start
|
cmp dword eax, _smol_start
|
||||||
jne short .looper
|
jne short .looper
|
||||||
sub esi, ebx
|
sub esi, ebx
|
||||||
sub esi, LM_ENTRY_OFFSET_BASE+4 ; +4: take inc-after from lodsb into acct
|
sub esi, LM_ENTRY_OFFSET_BASE+4 ; +4: take inc-after from lodsd into acct
|
||||||
|
|
||||||
xchg ebp, ebx
|
xchg ebp, ebx
|
||||||
xchg ebx, esi
|
xchg ebx, esi
|
||||||
|
@ -30,24 +31,17 @@ link: ; (struct link_map *root, char *symtable)
|
||||||
mov esi, [ebp + LM_NAME_OFFSET]
|
mov esi, [ebp + LM_NAME_OFFSET]
|
||||||
|
|
||||||
.basename: ; (const char *s (esi))
|
.basename: ; (const char *s (esi))
|
||||||
push esi
|
|
||||||
push edi
|
|
||||||
mov edi, esi
|
mov edi, esi
|
||||||
.basename.cmp:
|
.basename.cmp:
|
||||||
lodsb
|
lodsb
|
||||||
or al, al
|
cmp al, '/'
|
||||||
jz short .basename.done
|
|
||||||
cmp al, 47 ; '/'
|
|
||||||
cmove edi, esi
|
cmove edi, esi
|
||||||
jmp short .basename.cmp
|
or al, al
|
||||||
|
jnz short .basename.cmp
|
||||||
.basename.done:
|
.basename.done:
|
||||||
xchg eax, edi
|
|
||||||
pop edi
|
|
||||||
pop esi
|
pop esi
|
||||||
.basename.end:
|
.basename.end:
|
||||||
|
|
||||||
mov edi, eax
|
|
||||||
pop esi
|
|
||||||
.strcmp: ; (const char *s1 (esi), const char *s2 (edi))
|
.strcmp: ; (const char *s1 (esi), const char *s2 (edi))
|
||||||
push esi
|
push esi
|
||||||
push edi
|
push edi
|
||||||
|
@ -77,7 +71,7 @@ link: ; (struct link_map *root, char *symtable)
|
||||||
.do_symbols: ; null byte means end of symbols for this library!
|
.do_symbols: ; null byte means end of symbols for this library!
|
||||||
lodsb
|
lodsb
|
||||||
test al, al
|
test al, al
|
||||||
jz short .next_library
|
jz short .do_library
|
||||||
push ebx
|
push ebx
|
||||||
xchg ebx, edi
|
xchg ebx, edi
|
||||||
|
|
||||||
|
@ -89,7 +83,7 @@ link: ; (struct link_map *root, char *symtable)
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
mov ebx, [ebp + edi + LM_NBUCKETS_OFFSET]
|
mov ebx, [ebp + edi + LM_NBUCKETS_OFFSET]
|
||||||
div ebx
|
div ebx
|
||||||
; eax = entry->l_gnu_buckets[eax]
|
; eax = entry->l_gnu_buckets[edx]
|
||||||
mov eax, [ebp + edi + LM_GNU_BUCKETS_OFFSET]
|
mov eax, [ebp + edi + LM_GNU_BUCKETS_OFFSET]
|
||||||
mov eax, [eax + edx * 4]
|
mov eax, [eax + edx * 4]
|
||||||
; *h |= 1
|
; *h |= 1
|
||||||
|
@ -119,14 +113,13 @@ link: ; (struct link_map *root, char *symtable)
|
||||||
add esi, 4
|
add esi, 4
|
||||||
jmp short link.do_symbols
|
jmp short link.do_symbols
|
||||||
inc esi
|
inc esi
|
||||||
link.next_library:
|
|
||||||
jmp link.do_library
|
|
||||||
link.done:
|
link.done:
|
||||||
|
|
||||||
;xor ebp, ebp ; let's put that burden on the user code, so they can leave
|
;xor ebp, ebp ; let's put that burden on the user code, so they can leave
|
||||||
; it out if they want to
|
; it out if they want to
|
||||||
|
|
||||||
sub esp, 20 ; put the stack where _stack (C code) expects it to be
|
pop edx ; _dl_fini
|
||||||
|
sub esp, 20 ; put the stack where _start (C code) expects it to be
|
||||||
; this can't be left out, because X needs the envvars
|
; this can't be left out, because X needs the envvars
|
||||||
|
|
||||||
;.loopme: jmp short .loopme
|
;.loopme: jmp short .loopme
|
|
@ -0,0 +1,172 @@
|
||||||
|
; vim: set ft=nasm:
|
||||||
|
|
||||||
|
%include "rtld.inc"
|
||||||
|
|
||||||
|
%ifdef ELF_TYPE
|
||||||
|
[section .text.startup.smol]
|
||||||
|
%else
|
||||||
|
; not defined -> debugging!
|
||||||
|
[section .text]
|
||||||
|
%endif
|
||||||
|
|
||||||
|
; rax: special op reg
|
||||||
|
;!rbx: ptrdiff_t glibc_vercompat_extra_hi_field_off
|
||||||
|
; rcx: special op reg
|
||||||
|
; rdx: special op reg
|
||||||
|
; rsi: special op reg
|
||||||
|
; rdi: struct link_map* root / special op reg
|
||||||
|
; rbp:
|
||||||
|
; r8 :
|
||||||
|
; r9 :
|
||||||
|
;!r10: struct link_map* entry + far correction factor
|
||||||
|
; r11: temp storage var
|
||||||
|
;!r12: struct link_map* entry
|
||||||
|
;!r13: _dl_fini address (reqd by the ABI)
|
||||||
|
|
||||||
|
%ifndef ELF_TYPE
|
||||||
|
extern _symbols
|
||||||
|
global _start
|
||||||
|
_start:
|
||||||
|
%endif
|
||||||
|
_smol_start:
|
||||||
|
xchg r13, rdx ; _dl_fini
|
||||||
|
|
||||||
|
mov r12, [rsp - 8] ; return address of _dl_init
|
||||||
|
mov r11d, dword [r12 - 20] ; decode part of 'mov rdi, [rel _rtld_global]'
|
||||||
|
mov r12, [r12 + r11 - 16] ; ???
|
||||||
|
; struct link_map* root = r12
|
||||||
|
;mov r12, rdi
|
||||||
|
mov rsi, r12
|
||||||
|
|
||||||
|
; size_t* field = (size_t*)root;
|
||||||
|
; for (; *field != _smol_start; ++field) ;
|
||||||
|
.next_off:
|
||||||
|
lodsq
|
||||||
|
cmp rax, _smol_start
|
||||||
|
jne short .next_off
|
||||||
|
|
||||||
|
; // rbx = offsetof(struct link_map* rsi, l_entry) - DEFAULT_OFFSET
|
||||||
|
; rbx = field - root - offsetof(struct link_map, l_entry)
|
||||||
|
sub rsi, r12
|
||||||
|
sub rsi, LF_ENTRY_OFF+8
|
||||||
|
xchg rbx, rsi
|
||||||
|
|
||||||
|
mov rsi, _symbols
|
||||||
|
|
||||||
|
; for (rsi = (uint8_t*)_symbols; *rsi; ++rsi) {
|
||||||
|
.next_needed:
|
||||||
|
cmp byte [rsi], 0
|
||||||
|
je .needed_end
|
||||||
|
|
||||||
|
; do { // iter over the link_map
|
||||||
|
.next_link:
|
||||||
|
; entry = entry->l_next;
|
||||||
|
mov r12, [r12 + L_NEXT_OFF] ; skip the first one (this is our main
|
||||||
|
; binary, it has no symbols)
|
||||||
|
|
||||||
|
; keep the current symbol in a backup reg
|
||||||
|
mov rdx, rsi
|
||||||
|
|
||||||
|
; r11 = basename(rsi = entry->l_name)
|
||||||
|
mov rsi, [r12 + L_NAME_OFF]
|
||||||
|
.basename:
|
||||||
|
mov r11, rsi
|
||||||
|
.basename.next:
|
||||||
|
lodsb
|
||||||
|
cmp al, '/'
|
||||||
|
cmove r11, rsi
|
||||||
|
or al, al
|
||||||
|
jnz short .basename.next
|
||||||
|
.basename.done:
|
||||||
|
|
||||||
|
; and place it back
|
||||||
|
mov rsi, rdx ; rsi == _symbol
|
||||||
|
|
||||||
|
; strcmp(rsi, r11) -> flags; rsi == first hash if matches
|
||||||
|
.strcmp:
|
||||||
|
lodsb
|
||||||
|
or al, al
|
||||||
|
jz short .strcmp.done
|
||||||
|
sub al, byte [r11]
|
||||||
|
cmovnz rsi, rdx
|
||||||
|
jnz short .next_link;.strcmp.done
|
||||||
|
inc r11
|
||||||
|
jmp short .strcmp
|
||||||
|
.strcmp.done:
|
||||||
|
|
||||||
|
;mov rsi, rdx
|
||||||
|
|
||||||
|
; if (strcmp(...)) goto next_link;
|
||||||
|
;cmovnz r12, [r12 + L_NEXT_OFF] ; this is guaranteed to be nonzero
|
||||||
|
;jnz short .next_link ; because otherwise ld.so would have complained
|
||||||
|
|
||||||
|
; now we have the right link_map of the library, so all we have
|
||||||
|
; to do now is to find the right symbol addresses corresponding
|
||||||
|
; to the hashes.
|
||||||
|
|
||||||
|
; do {
|
||||||
|
.next_hash:
|
||||||
|
; if (!*phash) break;
|
||||||
|
lodsq
|
||||||
|
or eax, eax
|
||||||
|
jz short .next_needed ; done the last hash, so move to the next lib
|
||||||
|
|
||||||
|
;link_symbol(struct link_map* entry = r12, size_t* phash = rsi, uint32_t hash = eax)
|
||||||
|
lea r10, [r12 + rbx]
|
||||||
|
|
||||||
|
mov r11, rax
|
||||||
|
; uint32_t bkt_ind(edx) = hash % entry->l_nbuckets
|
||||||
|
xor edx, edx
|
||||||
|
mov ecx, dword [r10 + LF_NBUCKETS_OFF]
|
||||||
|
div ecx
|
||||||
|
|
||||||
|
; shift left because we don't want to compare the lowest bit
|
||||||
|
shr r11, 1
|
||||||
|
|
||||||
|
; uint32_t bucket(edx) = entry->l_gnu_buckets[bkt_ind]
|
||||||
|
mov r8, [r10 + LF_GNU_BUCKETS_OFF]
|
||||||
|
mov edx, dword [r8 + rdx * 4]
|
||||||
|
|
||||||
|
; do {
|
||||||
|
.next_chain:
|
||||||
|
; uint32_t luhash(ecx) = entry->l_gnu_chain_zero[bucket] >> 1
|
||||||
|
mov rcx, [r10 + LF_GNU_CHAIN_ZERO_OFF]
|
||||||
|
mov ecx, dword [rcx + rdx * 4]
|
||||||
|
shr ecx, 1
|
||||||
|
|
||||||
|
; if (luhash == hash) break;
|
||||||
|
cmp ecx, r11d
|
||||||
|
je short .chain_break
|
||||||
|
; ++bucket; } while (1);
|
||||||
|
inc edx
|
||||||
|
jne short .next_chain
|
||||||
|
|
||||||
|
.chain_break:
|
||||||
|
; ElfW(Sym)* symtab = entry->l_info[DT_SYMTAB]->d_un.d_ptr
|
||||||
|
; ElfW(Sym)* sym = &symtab[bucket]
|
||||||
|
; *phash = sym->st_value + entry->l_addr
|
||||||
|
|
||||||
|
; ElfW(Dyn)* dyn(rax) = entry->l_info[DT_SYMTAB]
|
||||||
|
mov rax, [r12 + L_INFO_DT_SYMTAB_OFF]
|
||||||
|
; ElfW(Sym)* symtab(rax) = dyn->d_un.d_ptr
|
||||||
|
mov rax, [rax + D_UN_PTR_OFF]
|
||||||
|
; ElfW(Addr) symoff(rax) = symtab[bucket].st_value
|
||||||
|
lea rdx, [rdx + rdx * 2]
|
||||||
|
mov rax, [rax + rdx * 8 + ST_VALUE_OFF]
|
||||||
|
; void* finaladdr(rax) = symoff + entry->l_addr
|
||||||
|
mov rcx, [r12 + L_ADDR_OFF]
|
||||||
|
add rax, rcx
|
||||||
|
|
||||||
|
; *phash = finaladdr
|
||||||
|
mov [rsi-8], rax
|
||||||
|
|
||||||
|
; } while (1)
|
||||||
|
jmp short .next_hash
|
||||||
|
|
||||||
|
.needed_end:
|
||||||
|
;xor rbp, rbp
|
||||||
|
mov rdi, rsp
|
||||||
|
push rax
|
||||||
|
xchg rsi, r13 ; _dl_fini
|
||||||
|
; fallthru to _start
|
||||||
|
|
26
src/rtld.inc
26
src/rtld.inc
|
@ -1,5 +1,6 @@
|
||||||
; vim: set ft=nasm:
|
; vim: set ft=nasm:
|
||||||
|
|
||||||
|
%if __BITS__ == 32
|
||||||
%define LM_NAME_OFFSET 0x4
|
%define LM_NAME_OFFSET 0x4
|
||||||
%define LM_NEXT_OFFSET 0xC
|
%define LM_NEXT_OFFSET 0xC
|
||||||
%define LM_ADDR_OFFSET 0
|
%define LM_ADDR_OFFSET 0
|
||||||
|
@ -15,6 +16,29 @@
|
||||||
%define DT_VALUE_OFFSET 0x4
|
%define DT_VALUE_OFFSET 0x4
|
||||||
%define DYN_PTR_OFFSET 0x4
|
%define DYN_PTR_OFFSET 0x4
|
||||||
|
|
||||||
%define DT_SYMTAB 0x6
|
|
||||||
%define DT_SYMSIZE_SHIFT 4
|
%define DT_SYMSIZE_SHIFT 4
|
||||||
|
|
||||||
|
%define DT_SYMTAB 0x6
|
||||||
|
|
||||||
|
%else
|
||||||
|
%define L_ADDR_OFF ( 0)
|
||||||
|
%define L_NAME_OFF ( 8)
|
||||||
|
%define L_NEXT_OFF ( 24)
|
||||||
|
%define L_INFO_OFF ( 64)
|
||||||
|
%define L_INFO_DT_SYMTAB_OFF (112)
|
||||||
|
|
||||||
|
%define LF_ENTRY_OFF (688)
|
||||||
|
%define LF_NBUCKETS_OFF (756)
|
||||||
|
%define LF_GNU_BUCKETS_OFF (776)
|
||||||
|
%define LF_GNU_CHAIN_ZERO_OFF (784)
|
||||||
|
|
||||||
|
%define L_GNU_BUCKETS_SZ ( 4)
|
||||||
|
%define L_GNU_CHAIN_ZERO_SZ ( 4)
|
||||||
|
|
||||||
|
%define D_UN_PTR_OFF ( 8)
|
||||||
|
%define ST_VALUE_OFF ( 8)
|
||||||
|
|
||||||
|
%define ELF_SYM_SZ ( 24)
|
||||||
|
%define ELF_DYN_SZ ( 16)
|
||||||
|
%endif
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ const char *f = "foo";
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
printf("hello world %s\n", f);
|
printf("hello world %s\n", f);
|
||||||
printf("argc=%d\n", argc);
|
printf("argc=%d\n", argc);
|
||||||
for (int i = 0; i < argc; ++i) printf("argv[%d]=%s\n", i, argv[i]);
|
printf("argv=%p\n", (void*)argv);
|
||||||
|
for (int i = 0; i < argc; ++i)
|
||||||
|
printf("argv[%d](%p)=%s\n", i, (void*)argv[i], argv[i]);
|
||||||
exit(42);
|
exit(42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
#include <stdio.h>
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
SDL_Window *w = SDL_CreateWindow("nice", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_OPENGL);
|
SDL_Window *w = SDL_CreateWindow("nice", SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_OPENGL);
|
||||||
|
printf("%s\n", "ohai");
|
||||||
SDL_Delay(3000);
|
SDL_Delay(3000);
|
||||||
SDL_DestroyWindow(w);
|
SDL_DestroyWindow(w);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue