diff options
author | Bobby Bingham <koorogi@koorogi.info> | 2017-01-15 22:25:00 -0600 |
---|---|---|
committer | Bobby Bingham <koorogi@koorogi.info> | 2017-01-15 23:19:46 -0600 |
commit | 578d71ea830823bd6bd27c9529075fbf18957c3b (patch) | |
tree | 6f3a5d5c1af94d4159f702bbfb30d3b8814859ba /nqdasm.c | |
parent | b908d08e19467a1dab76cd6bd26c43048dba4f7b (diff) |
nqdasm: Generate necessary labels for pcoff operands
Diffstat (limited to 'nqdasm.c')
-rw-r--r-- | nqdasm.c | 49 |
1 files changed, 48 insertions, 1 deletions
@@ -28,6 +28,7 @@ struct line { const struct mnemonic *mnem; uint16_t addr; uint16_t value; + int label; }; static const struct mnemonic *match_instruction(unsigned bits) @@ -51,6 +52,41 @@ static inline int get_argvalue(const struct line *line, int argidx) assert(0); } +static int cmp_line_addr(const void *a, const void *b) +{ + const struct line *la = (const struct line*)a; + const struct line *lb = (const struct line*)b; + return la->addr < lb->addr ? -1 : la->addr == lb->addr ? 0 : 1; +} + +static struct line *get_pcoff_target(const struct line *lines, size_t count, const struct line *inst, int argidx) +{ + uint16_t targetaddr = inst->addr + get_argvalue(inst, argidx); + return bsearch(&(struct line){ .addr = targetaddr }, lines, count, sizeof *lines, cmp_line_addr); +} + +static void assign_labels(struct line *lines, size_t count) +{ + /* mark those addresses that need a label */ + for (size_t i = 0; i < count; i++) { + if (!lines[i].mnem) continue; + + const struct operand *ops = lines[i].mnem->operands; + for (int j = 0; j < 3 && ops[j].type; j++) { + if (ops[j].type == PCOFF) { + struct line *target = get_pcoff_target(lines, count, lines + i, j); + if (target) target->label = 1; + } + } + } + + /* assign labels in ascending order */ + int label = 0; + for (size_t i = 0; i < count; i++) { + lines[i].label = lines[i].label ? label++ : -1; + } +} + static void print_operand(FILE *out, const struct line *lines, size_t count, size_t lineidx, size_t argidx) { const struct line *inst = lines + lineidx; @@ -60,7 +96,14 @@ static void print_operand(FILE *out, const struct line *lines, size_t count, siz case REG: fprintf(out, "r%d", get_argvalue(inst, argidx)); break; case REGPTR: fprintf(out, "@r%d", get_argvalue(inst, argidx)); break; case IMM: fprintf(out, "%d", get_argvalue(inst, argidx)); break; - case PCOFF: fprintf(out, "%d", get_argvalue(inst, argidx)); break; + case PCOFF: { + const struct line *target = get_pcoff_target(lines, count, inst, argidx); + if (target && target->label >= 0) + fprintf(out, "L%d", target->label); + else + fprintf(out, "%d", get_argvalue(inst, argidx)); + break; + } default: assert(0); } } @@ -114,11 +157,15 @@ static void disassemble(FILE *in, FILE *out) struct line *lines = read_lines(in, &count); if (!lines) return; + assign_labels(lines, count); + for (size_t i = 0; i < count; i++) { const struct line *line = lines + i; unsigned bits = line->value; const struct mnemonic *m = line->mnem; + if (line->label >= 0) fprintf(out, "L%d:", line->label); + if (!m) { fprintf(out, "\t.word 0x%04x\n", bits); continue; |