From 1a44036a174795fb8fc923625b6d720062f3d2d3 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 1 Feb 2017 10:36:06 -0500 Subject: [PATCH] In PowerPC as, check relocations with hi16/ha16/lo16. Check that each relocation meets the requirements for RELOPPC, which handles a hi16/lo16 or ha16/lo16 pair. In the code, one might confuse hi_token with hl_token and hi_expr with hl_expr, but I didn't think of better names for these variables. --- mach/powerpc/as/mach0.c | 3 + mach/powerpc/as/mach1.c | 1 + mach/powerpc/as/mach5.c | 144 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 140 insertions(+), 8 deletions(-) diff --git a/mach/powerpc/as/mach0.c b/mach/powerpc/as/mach0.c index 1c2051753..4e2e4ebe2 100644 --- a/mach/powerpc/as/mach0.c +++ b/mach/powerpc/as/mach0.c @@ -25,6 +25,9 @@ #undef ALIGNSECT #define ALIGNSECT 4 +#undef machfinish +/* machfinish() in mach5.c */ + #undef VALWIDTH #define VALWIDTH 8 diff --git a/mach/powerpc/as/mach1.c b/mach/powerpc/as/mach1.c index 50f799684..10e7a2b5f 100644 --- a/mach/powerpc/as/mach1.c +++ b/mach/powerpc/as/mach1.c @@ -10,3 +10,4 @@ void no_hl(void); word_t eval_hl(struct expr_t* expr, int token); void emit_hl(word_t in); +void machfinish(int n); diff --git a/mach/powerpc/as/mach5.c b/mach/powerpc/as/mach5.c index 222508d21..3029b7ddc 100644 --- a/mach/powerpc/as/mach5.c +++ b/mach/powerpc/as/mach5.c @@ -1,6 +1,22 @@ +/* + * We use RELOPPC to relocate hi16[expr] or ha16[expr]. This requires + * a matching lo16[expr] in the next instruction, because RELOPPC + * handles a hi16/lo16 or ha16/lo16 pair. RELOPPC only works with + * certain specific opcodes. + */ + +/* Info about the current hi16, ha16, or lo16 */ static int hl_token; static expr_t hl_expr; +/* Info about the last hi16 or ha16 */ +static int hi_token = 0; +static expr_t hi_expr; +static valu_t hi_relonami; +static long hi_lineno; +static ADDR_T hi_dotval; +static short hi_dottyp; + void no_hl(void) { hl_token = 0; } @@ -33,26 +49,138 @@ word_t eval_hl(expr_t* expr, int token) } } +static const char *hi_name(void) +{ + return hi_token == OP_HI ? "hi16" : "ha16"; +} + +static void cant_use_hl(const char *what) +{ + serror("can't use %s in this instruction", what); +} + +static void check_hl_expr(void) +{ + int und = ((hi_expr.typ & S_TYP) == S_UND); + int com = (hi_expr.typ & S_COM); + + if (hi_expr.typ != hl_expr.typ || + hi_expr.val != hl_expr.val || + ((und || com) && hi_relonami != relonami)) { + + long old = lineno; + lineno = hi_lineno; + serror("%s and lo16 must use same expression", hi_name()); + lineno = old; + } +} + +static void hi_missing_lo(void) +{ + long old = lineno; + lineno = hi_lineno; + serror("%s needs lo16 in next instruction", hi_name()); + lineno = old; +} + +static void need_hi(const char *needed, const char *got) +{ + long old = lineno; + lineno = hi_lineno; + serror("need %s, not %s, here", needed, got); + lineno = old; +} + void emit_hl(word_t in) { + word_t opcode; int type; switch (hl_token) { case OP_HI: case OP_HA: + /* hi16[...] or ha16[...] */ type = hl_expr.typ & S_TYP; - if (type != S_ABS) + if (type != S_ABS && PASS_RELO) { + if (hi_token) + hi_missing_lo(); + + opcode = in >> 26; + if (opcode != 15 /* addis */) + cant_use_hl(hi_name()); + + /* This hi16 or ha16 needs a lo16 in the next instruction. + * Save this info until we find the lo16. + */ + hi_token = hl_token; + hi_expr = hl_expr; + hi_relonami = relonami; + hi_lineno = lineno; + hi_dotval = DOTVAL; + hi_dottyp = DOTTYP; + + /* Relocate this hi16 or ha16 and the next lo16. */ newrelo(hl_expr.typ, RELOPPC | FIXUPFLAGS); - break; + } + break; case OP_LO: - /* If the assembler stored a symbol for relocation later, we - * need to abandon it (because the relocation was generated by - * hi16 or ha16). */ + /* lo16[...] */ type = hl_expr.typ & S_TYP; - if (type != S_ABS) - relonami = 0; - break; + if (type != S_ABS && PASS_RELO) { + if (hi_token) { + /* The last hi16 or ha16 needs this lo16 in the next + * instruction, to complete the pair for RELOPPC. + */ + if (DOTVAL != hi_dotval + 4 || DOTTYP != hi_dottyp) + hi_missing_lo(); + + check_hl_expr(); + + opcode = in >> 26; + switch (opcode) { + case 14: /* addi */ + case 34: /* lbz */ + case 48: /* lfs */ + case 50: /* lfd */ + case 42: /* lha */ + case 40: /* lhz */ + case 32: /* lwz */ + case 38: /* stb */ + case 52: /* stfs */ + case 54: /* stfd */ + case 44: /* sth */ + case 36: /* stw */ + if (hi_token == OP_HI) + need_hi("ha16", "hi16"); + break; + case 24: /* ori */ + if (hi_token == OP_HA) + need_hi("hi16", "ha16"); + break; + default: + cant_use_hl("lo16"); + } + + hi_token = 0; + + /* If we have a symbol for relocation, we need to + * abandon it (because the relocation was generated by + * hi16 or ha16). + */ + relonami = 0; + } else { + serror("lo16 without hi16 or ha16"); + } + } + break; } emit4(in); } + +void machfinish(int n) { + if (hi_token) { + hi_missing_lo(); + hi_token = 0; + } +} -- 2.34.1