From 3f8fed53587e406415945389243dd18284a20939 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 8 Apr 2011 02:44:21 +0200 Subject: [PATCH] ARM: Add pc-relative loads to DynASM. --- dynasm/dasm_arm.h | 20 +++++++++---- dynasm/dasm_arm.lua | 70 ++++++++++++++++++++++++--------------------- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/dynasm/dasm_arm.h b/dynasm/dasm_arm.h index 3fd795b7..87db7f00 100644 --- a/dynasm/dasm_arm.h +++ b/dynasm/dasm_arm.h @@ -360,7 +360,7 @@ int dasm_encode(Dst_DECL, void *buffer) case DASM_STOP: case DASM_SECTION: goto stop; case DASM_ESC: *cp++ = *p++; break; case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); goto patchrel; case DASM_ALIGN: ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; @@ -369,10 +369,18 @@ int dasm_encode(Dst_DECL, void *buffer) CK(n >= 0, UNDEF_LG); case DASM_REL_PC: CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); + n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; patchrel: - CK((n & 3) == 0 && ((n-4+0x02000000) >> 26) == 0, RANGE_REL); - cp[-1] |= (((n-4) >> 2) & 0x00ffffff); + if ((ins & 0x800) == 0) { + CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); + cp[-1] |= ((n >> 2) & 0x00ffffff); + } else if ((ins & 0x1000)) { + CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); + goto patchimml8; + } else { + CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); + goto patchimml12; + } break; case DASM_LABEL_LG: ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); @@ -387,11 +395,11 @@ int dasm_encode(Dst_DECL, void *buffer) case DASM_IMM16: cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); break; - case DASM_IMML8: + case DASM_IMML8: patchimml8: cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : ((-n & 0x0f) | ((-n & 0xf0) << 4)); break; - case DASM_IMML12: + case DASM_IMML12: patchimml12: cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); break; default: *cp++ = ins; break; diff --git a/dynasm/dasm_arm.lua b/dynasm/dasm_arm.lua index 243cfe90..1876078b 100644 --- a/dynasm/dasm_arm.lua +++ b/dynasm/dasm_arm.lua @@ -586,6 +586,36 @@ local function parse_shift(shift, gprok) end end +local function parse_label(label, def) + local prefix = sub(label, 1, 2) + -- =>label (pc label reference) + if prefix == "=>" then + return "PC", 0, sub(label, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "LG", map_global[sub(label, 3)] + end + if def then + -- [1-9] (local label definition) + if match(label, "^[1-9]$") then + return "LG", 10+tonumber(label) + end + else + -- [<>][1-9] (local label reference) + local dir, lnum = match(label, "^([<>])([1-9])$") + if dir then -- Fwd: 1-9, Bkwd: 11-19. + return "LG", lnum + (dir == ">" and 0 or 10) + end + -- extern label (extern label reference) + local extname = match(label, "^extern%s+(%S+)$") + if extname then + return "EXT", map_extern[extname] + end + end + werror("bad label `"..label.."'") +end + local function parse_load(params, nparams, n, op) local oplo = op % 256 local ext, ldrd = (oplo ~= 0), (oplo == 208) @@ -594,11 +624,17 @@ local function parse_load(params, nparams, n, op) d = ((op - (op % 4096)) / 4096) % 16 if d % 2 ~= 0 then werror("odd destination register") end end - local p1, wb = match(params[n], "^%[%s*(.-)%s*%](!?)$") + local pn = params[n] + local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") local p2 = params[n+1] if not p1 then if not p2 then - local reg, tailr = match(params[n], "^([%w_:]+)%s*(.*)$") + if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then + local mode, n, s = parse_label(pn, false) + waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) + return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) + end + local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") if reg and tailr ~= "" then local d, tp = parse_gpr(reg) if tp then @@ -653,36 +689,6 @@ local function parse_load(params, nparams, n, op) return op end -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - ------------------------------------------------------------------------------ -- Handle opcodes defined with template strings.