kulp / tenyr
1
#define _XOPEN_SOURCE (700) /* for strdup */
2

3
#include "asmif.h"
4
#include "ops.h"
5
// obj.h is included for RLC_* flags ; reconsider their location
6
#include "obj.h"
7
#include "parser.h"
8
#include "parser_global.h"
9
#include "expr.h"
10
#include "lexer.h"
11
#include "common.h"
12
#include "asm.h"
13

14
#include <stdlib.h>
15
#include <getopt.h>
16
#include <search.h>
17
#include <string.h>
18
#include <strings.h>
19
#include <assert.h>
20

21
static int ce_eval(struct parse_data *pd, struct element *context,
22
        struct const_expr *ce, int flags, int width, int shift, int32_t *result);
23

24 1
struct symbol *symbol_find(struct symbol_list *list, const char *name)
25
{
26 1
    list_foreach(symbol_list, elt, list)
27 1
        if (!strcmp(elt->symbol->name, name))
28 1
            return elt->symbol;
29

30 1
    return NULL;
31
}
32

33
// symbol_lookup returns 1 on success
34 1
static int symbol_lookup(struct parse_data *pd, struct symbol_list *list, const
35
        char *name, int32_t *result)
36
{
37 1
    struct symbol *symbol = NULL;
38 1
    if ((symbol = symbol_find(list, name))) {
39 1
        if (symbol->ce) {
40 1
            if (symbol->name && !strcmp(symbol->name, name))
41 1
                fatal(0, "Bad use before definition of symbol `%s'", name);
42

43 0
            struct element_list **prev = symbol->ce->deferred;
44 0
            return ce_eval(pd, (*prev)->elem, symbol->ce, 0, 0, 0, result);
45
        } else {
46 1
            *result = symbol->reladdr;
47
        }
48 1
        return 1;
49
    }
50

51
    // unresolved symbols get a zero value, but this is still success in CE_EXT
52
    // case (not in CE_SYM case)
53 1
    *result = 0;
54 1
    return 0;
55
}
56

57
// add_relocation returns 1 on success
58 1
static int add_relocation(struct reloc_list **relocs, const char *name,
59
        struct element *in, int width, int shift, int flags)
60
{
61 1
    if (!in)
62 1
        return 0;
63

64 1
    struct reloc_list *node = calloc(1, sizeof *node);
65

66 1
    node->reloc.name  = name ? strdup(name) : NULL;
67 1
    node->reloc.insn  = in;
68 1
    node->reloc.width = width;
69 1
    node->reloc.shift = shift;
70 1
    node->reloc.flags = flags;
71

72 1
    node->next = *relocs;
73 1
    *relocs = node;
74 1
    in->reloc = &node->reloc;
75

76 1
    return 1;
77
}
78

79 1
static int sym_reloc_handler(struct reloc_list **relocs, struct element *context,
80
        int flags, struct const_expr *ce, int width, int shift)
81
{
82 1
    int rlc_flags    = (flags & RHS_NEGATE    ) ? RLC_NEGATE : 0;
83 1
    const char *name = (flags & NO_NAMED_RELOC) ? NULL : *ce->symbol_name;
84

85 1
    return add_relocation(relocs, name, context, width, shift, rlc_flags);
86
}
87

88 1
int ce_eval_const(struct parse_data *pd, struct const_expr *ce,
89
        int32_t *result)
90
{
91 1
    int rc = ce_eval(pd, NULL, ce, 0, 0, 0, result);
92 1
    return rc;
93
}
94

95 1
static int ce_eval_sym(struct parse_data *pd, struct element *context,
96
        struct const_expr *ce, int flags, int width, int shift, int32_t *result)
97
{
98 1
    int relocate = (flags & DO_RELOCATION) != 0;
99 1
    if (ce->symbol && ce->symbol->ce) {
100 1
        struct element_list *deferred = *ce->symbol->ce->deferred;
101 1
        if (!deferred)
102 1
            return 0; // cannot evaluate yet
103 1
        struct element *dc = deferred->elem;
104 1
        return ce_eval(pd, dc, ce->symbol->ce, flags, width, shift, result)
105 1
            || (relocate ? sym_reloc_handler(&pd->relocs, dc, flags, ce, width, shift) : 0);
106
    } else {
107 1
        int found = symbol_lookup(pd, pd->symbols, *ce->symbol_name, result);
108 1
        if (relocate && ce->type == CE_EXT) {
109 1
            int hflags = flags | (found ? NO_NAMED_RELOC : 0);
110 1
            return sym_reloc_handler(&pd->relocs, context, hflags, ce, width, shift);
111
        }
112 1
        return found;
113
    }
114
}
115

116 1
static int ce_eval_op2(struct parse_data *pd, struct element *context,
117
        struct const_expr *ce, int flags, int width, int shift, int32_t *result)
118
{
119
    int32_t left, right;
120 1
    int rhsflags = flags;
121 1
    if (ce->op == '-')
122 1
        rhsflags ^= RHS_NEGATE;
123
    // "shift" can only apply to a left-hand-side
124 1
    int rrc = ce_eval(pd, context, ce->right, rhsflags, width,     0, &right);
125 1
    if (ce->op == RSHA) shift += right;
126 1
    int lrc = ce_eval(pd, context, ce->left ,    flags, width, shift, &left );
127 1
    if (rrc && lrc) {
128 1
        switch (ce->op) {
129 1
            case '+' : *result = left +  right; return 1;
130 1
            case '-' : *result = left -  right; return 1;
131 1
            case '*' : *result = left *  right; return 1;
132 1
            case '^' : *result = left ^  right; return 1;
133 1
            case '&' : *result = left &  right; return 1;
134 1
            case '|' : *result = left |  right; return 1;
135 1
            case LSH : *result = (int32_t)(((uint32_t)left) << right); return 1;
136 1
            case RSHA: *result = left >> right; return 1;
137 1
            case RSH : *result = (int32_t)(((uint32_t)left) >> right); return 1;
138 1
            case '/' :
139 1
                if (right == 0)
140 1
                    fatal(0, "Constant expression attempted %d/%d", left, right);
141 1
                *result = left / right;
142 1
                return 1;
143
// LCOV_EXCL_START
144
            default:
145
                fatal(0, "Unrecognised const_expr op '%c' (%#x)", ce->op, ce->op);
146
// LCOV_EXCL_STOP
147
        }
148
    }
149 1
    return 0;
150
}
151

152 1
static int ce_eval_op1(struct parse_data *pd, struct element *context,
153
        struct const_expr *ce, int flags, int width, int shift, int32_t *result)
154
{
155 1
    if (!ce_eval(pd, context, ce->left, flags, width, shift, result))
156 1
        return 0;
157 1
    switch (ce->op) {
158 1
        case '-': *result = -*result; return 1;
159 1
        case '~': *result = ~*result; return 1;
160
// LCOV_EXCL_START
161
        default : fatal(0, "Unrecognised const_expr op '%c' (%#x)", ce->op, ce->op);
162
// LCOV_EXCL_STOP
163
    }
164
}
165

166 1
static int ce_eval_ici(struct parse_data *pd, struct element *context,
167
        struct const_expr *ce, int flags, int width, int shift, int32_t *result)
168
{
169 1
    int relocate = (flags & DO_RELOCATION) != 0;
170 1
    if (!context)
171 1
        return 0;
172 1
    *result = context->insn.reladdr;
173 1
    return !relocate || sym_reloc_handler(&pd->relocs, context, flags, ce, width, shift);
174
}
175

176 1
static int ce_eval_imm(struct parse_data *pd, struct element *context,
177
        struct const_expr *ce, int flags, int width, int shift, int32_t *result)
178
{
179 1
    *result = ce->i;
180 1
    return 1;
181
}
182

183
typedef int ce_evaluator(struct parse_data *pd, struct element *context,
184
        struct const_expr *ce, int flags, int width, int shift, int32_t *result);
185
static ce_evaluator * const ce_eval_dispatch[CE_max] = {
186
    [CE_OP1] = ce_eval_op1,
187
    [CE_OP2] = ce_eval_op2,
188
    [CE_SYM] = ce_eval_sym,
189
    [CE_EXT] = ce_eval_sym,
190
    [CE_IMM] = ce_eval_imm,
191
    [CE_ICI] = ce_eval_ici,
192
};
193

194
// ce_eval should be idempotent. returns 1 on fully-successful evaluation, 0 on incomplete evaluation
195 1
static int ce_eval(struct parse_data *pd, struct element *context,
196
        struct const_expr *ce, int flags, int width, int shift, int32_t *result)
197
{
198
    assert(ce->type > CE_INVALID);
199
    assert(ce->type < CE_max);
200 1
    return ce_eval_dispatch[ce->type](pd, context, ce, flags, width, shift, result);
201
}
202

203 1
void ce_free(struct const_expr *ce)
204
{
205 1
    if (!ce)
206 1
        return;
207

208 1
    free(ce->deferred_name);
209

210 1
    if (ce->symbol) {
211 1
        ce_free(ce->symbol->ce);
212 1
        ce->symbol->ce = NULL;
213
    }
214

215 1
    ce_free(ce->right);
216 1
    ce_free(ce->left);
217

218 1
    free(ce);
219
}
220

221 1
static int fixup_deferred_exprs(struct parse_data *pd)
222
{
223 1
    int rc = 0;
224

225 1
    list_foreach(deferred_expr, r, pd->defexprs) {
226 1
        struct const_expr *ce = r->ce;
227

228
        int32_t result;
229 1
        if (ce_eval(pd, ce->insn, ce, DO_RELOCATION, r->width, 0, &result)) {
230 1
            result *= r->mult;
231

232
            // XXX handle too-large values in a 32-bit field
233
            // .word 0x123456123456 # this fails to provoke an error
234 1
            const char *sstr = (r->width < 32) ? "signed " : "";
235 1
            if (!(ce->flags & IGNORE_WIDTH) && result != SEXTEND32((unsigned)r->width, result)) {
236 1
                debug(0, "Expression resulting in value %#x is too large for "
237
                        "%d-bit %simmediate field", result, r->width, sstr);
238 1
                rc |= 1;
239
            }
240

241
            // The mask may need to be all ones, so we need to compute the mask
242
            // in a space larger than 32 bits, before truncating it.
243 1
            int32_t mask = (int32_t)~((1LL << r->width) - 1);
244 1
            *r->dest &= mask;
245 1
            *r->dest |= result & ~mask;
246 1
            ce_free(ce);
247
        } else {
248 1
            fatal(0, "Error while fixing up deferred expressions");
249
            // TODO print out information about the deferred expression
250
        }
251

252 1
        free(r);
253
    }
254

255 1
    return rc;
256
}
257

258 1
static int mark_globals(struct symbol_list *symbols, struct global_list *globals)
259
{
260
    struct symbol *which;
261 1
    list_foreach(global_list, g, globals)
262 1
        if ((which = symbol_find(symbols, g->name)))
263 1
            which->global = 1;
264
        else
265 1
            debug(0, "Symbol `%s' was marked as a global, but was not defined",
266
                    g->name);
267

268 1
    return 0;
269
}
270

271 1
static int check_symbols(struct symbol_list *symbols)
272
{
273 1
    int rc = 0;
274

275
    // check for and reject duplicates
276 1
    void *tree = NULL;
277 1
    list_foreach(symbol_list, Node, symbols) {
278 1
        if (!Node->symbol->unique)
279 1
            continue;
280

281 1
        const char **name = tsearch(Node->symbol->name, &tree, (cmp*)strcmp);
282

283 1
        if (*name != Node->symbol->name) {
284 1
            rc = 1;
285 1
            break;
286
        }
287
    }
288

289
    // delete entire tree
290 1
    while (tree)
291 1
        tdelete(*(void**)tree, &tree, (cmp*)strcmp);
292

293 1
    return rc;
294
}
295

296 1
static int assembly_cleanup(struct parse_data *pd)
297
{
298 1
    list_foreach(element_list, Node, pd->top) {
299 1
        free(Node->elem);
300 1
        free(Node);
301
    }
302

303 1
    list_foreach(symbol_list, Node, pd->symbols) {
304 1
        if (Node->symbol) {
305 1
            ce_free(Node->symbol->ce);
306 1
            free(Node->symbol->name);
307
        }
308 1
        free(Node->symbol);
309 1
        free(Node);
310
    }
311

312 1
    list_foreach(global_list, Node, pd->globals) {
313 1
        free(Node->name);
314 1
        free(Node);
315
    }
316

317 1
    list_foreach(reloc_list, Node, pd->relocs) {
318 1
        free(Node->reloc.name);
319 1
        free(Node);
320
    }
321

322 1
    return 0;
323
}
324

325 1
static int assembly_fixup_insns(struct parse_data *pd)
326
{
327 1
    int32_t reladdr = 0;
328
    // first pass, fix up addresses
329 1
    list_foreach(element_list, il, pd->top) {
330 1
        il->elem->insn.reladdr = reladdr;
331

332 1
        list_foreach(symbol, l, il->elem->symbol) {
333 1
            l->reladdr = reladdr;
334 1
            l->resolved = 1;
335
        }
336

337 1
        reladdr += il->elem->insn.size;
338
    }
339

340 1
    list_foreach(symbol_list, li, pd->symbols)
341 1
        list_foreach(symbol, l, li->symbol)
342 1
            if (!l->resolved)
343 1
                if (ce_eval(pd, NULL, l->ce, DO_RELOCATION, WORD_BITWIDTH, 0, &l->reladdr))
344 1
                    l->resolved = 1;
345

346 1
    return 0;
347
}
348

349 1
static int assembly_inner(struct parse_data *pd, STREAM *out, const struct format *f, void *ud)
350
{
351 1
    assembly_fixup_insns(pd);
352

353 1
    mark_globals(pd->symbols, pd->globals);
354 1
    if (check_symbols(pd->symbols))
355 1
        fatal(0, "Error in symbol processing : check for duplicate symbols");
356

357 1
    if (fixup_deferred_exprs(pd))
358 1
        fatal(0, "Error while fixing up deferred expressions");
359

360 1
    list_foreach(element_list, Node, pd->top)
361 1
        f->out(out, Node->elem, ud);
362

363 1
    if (f->sym) {
364 1
        list_foreach(symbol_list, Node, pd->symbols) {
365 1
            int flags = 0;
366 1
            struct symbol *sym = Node->symbol;
367 1
            if (sym->ce && (sym->ce->flags & IS_DEFERRED) == 0)
368 1
                flags |= RLC_ABSOLUTE;
369

370 1
            f->sym(out, sym, flags, ud);
371
        }
372
    }
373

374 1
    if (f->reloc)
375 1
        list_foreach(reloc_list, Node, pd->relocs)
376 1
            f->reloc(out, &Node->reloc, ud);
377

378 1
    assembly_cleanup(pd);
379

380 1
    return 0;
381
}
382

383 1
int do_assembly(STREAM *in, STREAM *out, const struct format *f, void *ud)
384
{
385 1
    struct parse_data _pd = {
386
        .top = NULL,
387 1
    }, *pd = &_pd;
388

389 1
    tenyr_lex_init(&pd->scanner);
390 1
    tenyr_set_extra(pd, pd->scanner);
391 1
    tenyr_set_in(in->ud, pd->scanner);
392

393 1
    int result = tenyr_parse(pd);
394 1
    if (pd->errored)
395 1
        debug(0, "Encountered %d error%s while parsing, bailing",
396
                pd->errored, &"s"[pd->errored == 1]);
397 1
    if (!result && !pd->errored)
398 1
        assembly_inner(pd, out, f, ud);
399 1
    tenyr_lex_destroy(pd->scanner);
400

401 1
    return result || pd->errored;
402
}
403

404
// Currently always returns success (zero). Should consider propagating errors.
405 1
int do_disassembly(STREAM *in, STREAM *out, const struct format *f, void *ud, int flags)
406
{
407 1
    int rc = 0;
408

409
    struct element i;
410 1
    while ((rc = f->in(in, &i, ud)) >= 0) {
411 1
        if (rc == 0)
412 1
            continue; // allow a format to emit no instructions
413 1
        int len = print_disassembly(out, &i, ASM_AS_INSN | flags);
414 1
        if (!(flags & ASM_QUIET)) {
415 1
            out->op.fprintf(out, "%*s# ", 30 - len, "");
416 1
            print_disassembly(out, &i, ASM_AS_DATA | flags);
417 1
            out->op.fprintf(out, " ; ");
418 1
            print_disassembly(out, &i, ASM_AS_CHAR | flags);
419 1
            out->op.fprintf(out, " ; .addr 0x%08x\n", i.insn.reladdr);
420
        } else {
421 1
            out->op.fwrite("\n", 1, 1, out);
422
            // This probably means we want line-oriented output
423 1
            out->op.fflush(out);
424
        }
425
    }
426

427 1
    return 0;
428
}
429

430
/* vi:set ts=4 sw=4 et: */

Read our documentation on viewing source code .

Loading