From db77f523365ed0093de8591118184003f82a9111 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 20 Sep 2018 01:50:01 +0100 Subject: [PATCH] fcc/libs: complete support for relocatable binaries Not yet fully tested and needs a small kernel change --- Library/Makefile | 7 +- Library/libs/Makefile.z80 | 16 +++- Library/libs/crt0_z80_rel.s | 122 +++++++++++++++++++++++++++++ Library/libs/crt0nostdio_z80_rel.s | 121 ++++++++++++++++++++++++++++ Library/tools/fcc.c | 7 +- Library/tools/relocbin.c | 13 ++- 6 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 Library/libs/crt0_z80_rel.s create mode 100644 Library/libs/crt0nostdio_z80_rel.s diff --git a/Library/Makefile b/Library/Makefile index 9c017bf8..41f1eae9 100644 --- a/Library/Makefile +++ b/Library/Makefile @@ -5,7 +5,7 @@ CFLAGS += -I../Kernel/include all: tools/syscall tools/binman tools/fcc tools/syscall_6502 \ tools/syscall_68000 \ tools/syscall_6809 tools/syscall-scc6809 tools/binman \ - tools/fcc tools/liberror + tools/fcc tools/liberror tools/relocbin clean: rm -f tools/syscall tools/binman tools/fcc tools/fsize tools/liberror @@ -35,6 +35,9 @@ tools/syscall_pdp11: tools/syscall_pdp11.c ../Kernel/include/syscall_name.h tools/binman: tools/binman.c $(CC) $(CFLAGS) -o $@ $< +tools/relocbin: tools/relocbin.c + $(CC) $(CFLAGS) -o $@ $< + tools/liberror: tools/liberror.c $(CC) $(CFLAGS) -o $@ $< @@ -45,7 +48,7 @@ ifeq ($(USERCPU),z80) mkdir -p /opt/fcc/include/6502 /opt/fcc/include/arpa mkdir -p /opt/fcc/include/msp430x /opt/fcc/include/netinet mkdir -p /opt/fcc/include/sys - install -m 0755 tools/binman tools/fcc /opt/fcc/bin + install -m 0755 tools/binman tools/relocbin tools/fcc /opt/fcc/bin install -m 0644 include/*.h /opt/fcc/include install -m 0644 include/6502/*.h /opt/fcc/include/6502 install -m 0644 include/arpa/*.h /opt/fcc/include/arpa diff --git a/Library/libs/Makefile.z80 b/Library/libs/Makefile.z80 index d9b806b4..27e54e1f 100644 --- a/Library/libs/Makefile.z80 +++ b/Library/libs/Makefile.z80 @@ -14,6 +14,10 @@ SRC_CRT0 = crt0$(PLATFORM).s OBJ_CRT0 = $(SRC_CRT0:.s=.rel) SRC_CRT0NS = crt0nostdio$(PLATFORM).s OBJ_CRT0NS = $(SRC_CRT0NS:.s=.rel) +SRC_CRT0R = crt0$(PLATFORM)_z80_rel.s +OBJ_CRT0R = $(SRC_CRT0R:.s=.rel) +SRC_CRT0NSR = crt0nostdio$(PLATFORM)_z80_rel.s +OBJ_CRT0NSR = $(SRC_CRT0NSR:.s=.rel) SRC_ASM = enter.s htonl-$(USERCPU).s htons-$(USERCPU).s OBJ_ASM = $(SRC_ASM:.s=.rel) SRC_C = __argv.c a64l.c abort.c aes256.c asctime.c assert.c atexit.c atoi_small.c @@ -98,7 +102,10 @@ OBJ_HARD = $(SRC_HARD:.c=.rel) OBJ_ALL = $(OBJ_ASM) $(OBJ_C) $(OBJ_HARD) OBJ_RES = $(SRC_RES:.c=.rel) -all: c$(PLATFORM).lib crt0$(PLATFORM).rel crt0nostdio$(PLATFORM).rel liberror.txt curses$(PLATFORM).lib termcap$(PLATFORM).lib m$(PLATFORM).lib tinymalloc$(PLATFORM).lib resolv$(PLATFORM).lib +all: c$(PLATFORM).lib crt0$(PLATFORM).rel crt0nostdio$(PLATFORM).rel \ + crt0$(PLATFORM)_z80_rel.rel crt0nostdio$(PLATFORM)_z80_rel.rel \ + liberror.txt curses$(PLATFORM).lib termcap$(PLATFORM).lib \ + m$(PLATFORM).lib tinymalloc$(PLATFORM).lib resolv$(PLATFORM).lib libc.l:%.l:$(OBJ_ALL) ls $(OBJ_ALL) > libc.l @@ -156,6 +163,12 @@ $(OBJ_CRT0):%.rel: %.s $(OBJ_CRT0NS):%.rel: %.s $(ASM) $(ASM_OPT) $@ $(@:.rel=.s) +$(OBJ_CRT0R):%.rel: %.s + $(ASM) $(ASM_OPT) $@ $(@:.rel=.s) + +$(OBJ_CRT0NSR):%.rel: %.s + $(ASM) $(ASM_OPT) $@ $(@:.rel=.s) + $(OBJ_C):%.rel: %.c $(CC) $(CC_OPT) $(@:.rel=.c) @@ -186,3 +199,4 @@ install: cp crt0$(PLATFORM).rel crt0nostdio$(PLATFORM).rel c$(PLATFORM).lib /opt/fcc/lib/ cp curses$(PLATFORM).lib termcap$(PLATFORM).lib /opt/fcc/lib/ cp m$(PLATFORM).lib tinymalloc$(PLATFORM).lib /opt/fcc/lib/ + cp crt0$(PLATFORM)_z80_rel.rel crt0nostdio$(PLATFORM)_z80_rel.rel /opt/fcc/lib/ diff --git a/Library/libs/crt0_z80_rel.s b/Library/libs/crt0_z80_rel.s new file mode 100644 index 00000000..9e154ae3 --- /dev/null +++ b/Library/libs/crt0_z80_rel.s @@ -0,0 +1,122 @@ + .module crt0_z80_rel + + .area _CODE + .area _HOME + .area _CONST + ; The _GS can be blown away after startup. We don't yet + ; but we should do FIXME + .area _GSINIT + .area _GSFINAL + .area _INITIALIZED + .area _BSEG + .area _DATA + .area _BSS + ; note that the binary builder moves the initialized data + ; from initializer + .area _INITIALIZER + + .globl ___stdio_init_vars + .globl _main + .globl _exit + .globl _environ + .globl ___argv + .globl s__DATA + + .area _CODE + +; start at 0x100 +start: jr start2 ; must be relative + nop + .db 'F' + .db 'Z' + .db 'X' + .db '1' + +; +; Borrowed idea from UMZIX - put the info in known places then +; we can write "size" tools +; +; This is confusing. SDCC doesn't produce a BSS, instead it +; produces an INITIALIZED (which everyone else calls DATA) and a +; DATA which everyone else would think of as BSS. +; +; FIXME: we need to automate the load page setting +; + .db 0x01 ; page to load at + .dw 0 ; chmem ("0 - 'all'") + ; These three are set by binman + .dw 0 ; code + .dw 0 ; data + .dw 0 ; bss size + .dw 0 ; spare + +start2: +; +; On entry we are page aligned and de is our base +; +; s__DATA is the BSS base computed by the compiler. It will get +; modified by the relocatable binary maker in the header but not +; in the code. Thus this is actually a pointer to our relocation +; bytestream. +; + ld hl,#s__DATA ; will be pre-reloc value (0 based) + add hl,de ; hl is now the relocations + ; de is the code base + ld b,#0 ; on the code base bits + ex de,hl ; de is relocatios as loop swaps +relnext: + ; Read each relocatin byte and zero it (because it's really + ; stolen BSS so should start zero) + ex de,hl + ld a,(hl) + inc hl + ld (hl),#0 + ex de,hl + ; 255 means done, 254 means skip 254, 253 or less means + ; skip that many and relocate (254 and reloc is encoded as + ; 254,0, long runs are 254,254,254,n... + cp #255 + jr z, relocdone + ld c,a + cp #254 + jr z, relocskip + add hl,bc + ld a,(hl) + add e + ld (hl),a + jr relnext +relocskip: add hl,bc + jr relnext +relocdone: +; ; At this point our calls are relocated so this will go to + ; the right place + call gsinit + + ld hl, #4 + add hl, sp + ld (_environ), hl + pop de ; argc + pop hl ; argv + push hl + ld (___argv), hl ; needed for stuff like err() + push de + call _main ; go + push hl + call _exit + + .area _GSINIT +; +; FIXME: we want to work this into the C code so it's not +; automatically sucking in any of stdio at all. +; +gsinit: + call ___stdio_init_vars +; +; Any gsinit code from other modules will accumulate between here +; and _GSFINAL to provide constructors and other ghastly C++isms +; + .area _GSFINAL + ret + + .area _DATA +_environ: .dw 0 diff --git a/Library/libs/crt0nostdio_z80_rel.s b/Library/libs/crt0nostdio_z80_rel.s new file mode 100644 index 00000000..c7da9bda --- /dev/null +++ b/Library/libs/crt0nostdio_z80_rel.s @@ -0,0 +1,121 @@ + .module crt0_z80_rel + + .area _CODE + .area _HOME + .area _CONST + ; The _GS can be blown away after startup. We don't yet + ; but we should do FIXME + .area _GSINIT + .area _GSFINAL + .area _INITIALIZED + .area _BSEG + .area _DATA + .area _BSS + ; note that the binary builder moves the initialized data + ; from initializer + .area _INITIALIZER + + .globl ___stdio_init_vars + .globl _main + .globl _exit + .globl _environ + .globl ___argv + .globl s__DATA + + .area _CODE + +; start at 0x100 +start: jr start2 ; must be relative + nop + .db 'F' + .db 'Z' + .db 'X' + .db '1' + +; +; Borrowed idea from UMZIX - put the info in known places then +; we can write "size" tools +; +; This is confusing. SDCC doesn't produce a BSS, instead it +; produces an INITIALIZED (which everyone else calls DATA) and a +; DATA which everyone else would think of as BSS. +; +; FIXME: we need to automate the load page setting +; + .db 0x01 ; page to load at + .dw 0 ; chmem ("0 - 'all'") + ; These three are set by binman + .dw 0 ; code + .dw 0 ; data + .dw 0 ; bss size + .dw 0 ; spare + +start2: +; +; On entry we are page aligned and de is our base +; +; s__DATA is the BSS base computed by the compiler. It will get +; modified by the relocatable binary maker in the header but not +; in the code. Thus this is actually a pointer to our relocation +; bytestream. +; + ld hl,#s__DATA ; will be pre-reloc value (0 based) + add hl,de ; hl is now the relocations + ; de is the code base + ld b,#0 ; on the code base bits + ex de,hl ; de is relocatios as loop swaps +relnext: + ; Read each relocatin byte and zero it (because it's really + ; stolen BSS so should start zero) + ex de,hl + ld a,(hl) + inc hl + ld (hl),#0 + ex de,hl + ; 255 means done, 254 means skip 254, 253 or less means + ; skip that many and relocate (254 and reloc is encoded as + ; 254,0, long runs are 254,254,254,n... + cp #255 + jr z, relocdone + ld c,a + cp #254 + jr z, relocskip + add hl,bc + ld a,(hl) + add e + ld (hl),a + jr relnext +relocskip: add hl,bc + jr relnext +relocdone: +; ; At this point our calls are relocated so this will go to + ; the right place + call gsinit + + ld hl, #4 + add hl, sp + ld (_environ), hl + pop de ; argc + pop hl ; argv + push hl + ld (___argv), hl ; needed for stuff like err() + push de + call _main ; go + push hl + call _exit + + .area _GSINIT +; +; FIXME: we want to work this into the C code so it's not +; automatically sucking in any of stdio at all. +; +gsinit: +; +; Any gsinit code from other modules will accumulate between here +; and _GSFINAL to provide constructors and other ghastly C++isms +; + .area _GSFINAL + ret + + .area _DATA +_environ: .dw 0 diff --git a/Library/tools/fcc.c b/Library/tools/fcc.c index 828728c1..cd570c5a 100644 --- a/Library/tools/fcc.c +++ b/Library/tools/fcc.c @@ -492,6 +492,9 @@ static void build_command(int pass) } } if (mode == MODE_LINK) { + char *rp = ""; + if (relocatable) + rp = "_z80_rel"; if (target == NULL) autotarget(); if (target == NULL) { @@ -500,9 +503,9 @@ static void build_command(int pass) } add_option("-o", relocmap(undotslash(target), pass)); if (nostdio) - snprintf(buf, sizeof(buf), FCC_DIR "/lib/crt0nostdio%s.rel", platform); + snprintf(buf, sizeof(buf), FCC_DIR "/lib/crt0%snostdio%s.rel", platform, rp); else - snprintf(buf, sizeof(buf), FCC_DIR "/lib/crt0%s.rel", platform); + snprintf(buf, sizeof(buf), FCC_DIR "/lib/crt0%s%s.rel", platform, rp); add_argument(mstrdup(buf)); } if (srchead) { diff --git a/Library/tools/relocbin.c b/Library/tools/relocbin.c index a41fc806..69701b26 100644 --- a/Library/tools/relocbin.c +++ b/Library/tools/relocbin.c @@ -12,7 +12,6 @@ static uint8_t buf[65536]; static uint8_t bufb[65536]; -static uint8_t reloc[65536]; static unsigned int s__INITIALIZER, s__INITIALIZED; static unsigned int l__INITIALIZER; @@ -21,8 +20,6 @@ static unsigned int s__DATA, l__DATA; static unsigned int progload = 0x100; -static unsigned char *relptr = reloc; - static void ProcessMap(FILE *fp) { char buf[512]; @@ -54,6 +51,8 @@ static void sweep_relocations(void) { uint8_t *base = buf + 0x0100; uint8_t *base2 = bufb + 0x0200; + uint8_t *relptr = buf + s__DATA; /* write relocs into BSS head */ + int relsize; int len = s__DATA - 0x0100; int pos = 0x0100; int lastrel = 0x0100; @@ -88,7 +87,13 @@ static void sweep_relocations(void) exit(1); } *relptr++ = 0xFF; -// printf("Relocations cost %d bytes.\n", relptr - reloc); + relsize = relptr - (buf + s__DATA); + /* In effect move the relocations from DATA into INITIALIZED */ + s__DATA += relsize; + l__DATA -= relsize; + /* Corner case - more relocations than data - grow the object size slightly */ + if (l__DATA < 0) + l__DATA = 0; } int main(int argc, char *argv[]) -- 2.34.1