diff options
| author | Andrew Chambers <[email protected]> | 2021-10-08 03:27:45 +1300 |
|---|---|---|
| committer | Andrew Chambers <[email protected]> | 2021-10-08 03:27:45 +1300 |
| commit | 7c8d5a28545bdaf7d2574fcde8867d12a13128f6 (patch) | |
| tree | efe338854f3a0dc161c949d81f266b5197451406 | |
| parent | 6526cddc058df5a1a84d7f4081e3f4a499642733 (diff) | |
Work on relocations.
| -rw-r--r-- | asm.peg | 30 | ||||
| -rw-r--r-- | main.c | 102 | ||||
| -rw-r--r-- | minias.h | 8 |
3 files changed, 106 insertions, 34 deletions
@@ -29,26 +29,32 @@ label = { $$.label = (Label){.kind = ASM_LABEL, .name = i.ident.name}; } instr = - "nop" { $$.kind = ASM_NOP; } + "nop" { $$.kind = ASM_NOP; } | "leave" { $$.kind = ASM_LEAVE; } - | "ret" { $$.kind = ASM_RET; } - | i:xchg { $$ = i; } - | i:add { $$ = i; } - | i:and { $$ = i; } - | i:lea { $$ = i; } - | i:mov { $$ = i; } - | i:or { $$ = i; } - | i:sub { $$ = i; } - | i:xor { $$ = i; } + | "ret" { $$.kind = ASM_RET; } + | i:jmp { $$ = i; } + | i:xchg { $$ = i; } + | i:add { $$ = i; } + | i:and { $$ = i; } + | i:lea { $$ = i; } + | i:mov { $$ = i; } + | i:or { $$ = i; } + | i:sub { $$ = i; } + | i:xor { $$ = i; } + + +jmp = + "jmp" ws t:ident + { $$.jmp = (Jmp){ .kind = ASM_JMP, .target=t.ident.name } ; } lea = - 'lea' ( + "lea" ( 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR(0, s, d); } | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR(1, s, d); } | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR(2, s, d); } ) { $$.instr.kind = ASM_LEA; } -#XXX Some other these rules can probably be collapsed. +#XXX Some of these rules can probably be collapsed (or expanded for simplicity?). mov = "mov" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR(0, s, d); } @@ -7,6 +7,11 @@ static AsmLine *allasm = NULL; // writing out the symtab section. static struct hashtable *symbols = NULL; +// Linked list of relocations +static Relocation *relocs = NULL; +static size_t nrelocs = 0; +static size_t reloccap = 0; + #define MAXSECTIONS 32 static Section sections[MAXSECTIONS]; static size_t nsections = 1; // first is reserved. @@ -116,6 +121,14 @@ static void initsections(void) { text->hdr.sh_addralign = 4; } +Relocation *newreloc() { + if (nrelocs == reloccap) { + reloccap = nrelocs ? nrelocs * 2 : 64; + relocs = xreallocarray(relocs, reloccap, sizeof(Relocation)); + } + return &relocs[nrelocs++]; +} + static Parsev *dupv(Parsev *p) { Parsev *r = xmalloc(sizeof(Parsev)); *r = *p; @@ -235,6 +248,18 @@ static void assembleplusr(uint8_t opcode, AsmKind reg) { } static void assembleimm(Imm *imm) { + Relocation *reloc; + Symbol *sym; + + if (imm->l != NULL) { + reloc = newreloc(); + sym = getsym(imm->l); + reloc->kind = 0; // XXX + reloc->section = cursection; + reloc->sym = sym; + reloc->offset = cursection->hdr.sh_size; + } + switch (imm->nbytes) { case 1: sb((uint8_t)imm->c); @@ -336,7 +361,7 @@ static void assemblerrm(Instr *instr, uint8_t opcode) { if ((rm & 7) == 4) lfatal("addressing mode unrepresentable"); if (memarg->c == 0 && memarg->l == NULL) { - if ((rm & 7) == 5) { // BP style registers need sib + if ((rm & 7) == 5) { /* BP style registers need sib */ mod = 0x01; wantsib = 1; sib = 0; @@ -416,7 +441,6 @@ static void assemble(void) { Symbol *sym; Parsev *v; AsmLine *l; - const char *label; cursection = text; @@ -425,8 +449,7 @@ static void assemble(void) { v = &l->v; switch (l->v.kind) { case ASM_DIR_GLOBL: - label = v->globl.name; - sym = getsym(label); + sym = getsym(v->globl.name); sym->global = 1; break; case ASM_DIR_DATA: @@ -450,9 +473,10 @@ static void assemble(void) { sb(v->byte.b); break; case ASM_LABEL: - label = v->label.name; - sym = getsym(label); + sym = getsym(v->label.name); + sym->section = cursection; sym->offset = cursection->hdr.sh_size; + sym->defined = 1; break; case ASM_NOP: sb(0x90); @@ -520,20 +544,17 @@ static void assemble(void) { break; } case ASM_JMP: { - int64_t distance; + Symbol *sym; + Relocation *reloc; + sb(0xe9); sym = getsym(v->jmp.target); - if (sym->section && (sym->section == cursection)) { - distance = sym->offset - cursection->hdr.sh_size; - } else { - distance = 0x7fffffff; // XXX - } - if (distance <= 128 && distance >= -127) { - sb2(0xeb, (uint8_t)distance); - } else { - sb(0xe9); - sw((uint32_t)distance); - } + reloc = newreloc(); + reloc->kind = 0; // XXX + reloc->section = cursection; + reloc->sym = sym; + reloc->offset = cursection->hdr.sh_size; + sw(0x00000000); break; } default: @@ -564,20 +585,57 @@ static void fillsymtab(void) { // Local symbols for (i = 0; i < symbols->cap; i++) { + if (!symbols->keys[i].str) + continue; sym = symbols->vals[i]; - if (!sym || sym->global || !sym->section) + if (sym->global || !sym->section) continue; addtosymtab(sym); } // Global symbols for (i = 0; i < symbols->cap; i++) { + if (!symbols->keys[i].str) + continue; sym = symbols->vals[i]; - if (!sym || !sym->global || !sym->section) + if (!sym->global || !sym->section) continue; addtosymtab(sym); } } +static void handlerelocs(void) { + Symbol *sym; + Relocation *reloc; + size_t i; + + for (i = 0; i < nrelocs; i++) { + reloc = &relocs[i]; + sym = reloc->sym; + if (sym->section == reloc->section) { + switch (reloc->kind) { + case 0: { + uint8_t *rdata; + int32_t addend, value; + rdata = &reloc->section->data[reloc->offset]; + addend = (int32_t)rdata[0] | (int32_t)(rdata[1] << 8) | + (int32_t)(rdata[2] << 16) | (int32_t)(rdata[3] << 24); + // XXX overflow? + value = sym->offset - (int32_t)reloc->offset + addend; + fprintf(stderr, "%lu %ld %d %d\n", reloc->offset, sym->offset, addend, + value); + rdata[0] = (value & 0xff); + rdata[1] = (value & 0xff00) >> 8; + rdata[2] = (value & 0xff000) >> 16; + rdata[3] = (value & 0xff00000) >> 24; + break; + } + default: + unreachable(); + } + } + } +} + static void out(uint8_t *buf, size_t n) { fwrite(buf, 1, n, outf); if (ferror(outf)) @@ -624,11 +682,11 @@ static void outelf(void) { int main(void) { symbols = mkhtab(256); outf = stdout; - initsections(); parse(); assemble(); - // fillsymtab(); + fillsymtab(); + handlerelocs(); outelf(); if (fflush(outf) != 0) fatal("fflush:"); @@ -24,9 +24,17 @@ typedef struct { int64_t offset; int64_t size; int global; + int defined; Section *section; } Symbol; +typedef struct { + Section *section; + Symbol *sym; + int kind; + uint64_t offset; +} Relocation; + typedef enum { // Misc ASM_SYNTAX_ERROR, |
