summaryrefslogtreecommitdiff
path: root/nqdasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'nqdasm.c')
-rw-r--r--nqdasm.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/nqdasm.c b/nqdasm.c
index e0f78fc..d7016fb 100644
--- a/nqdasm.c
+++ b/nqdasm.c
@@ -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;