Parcourir la source

ARM: Add pc-relative loads to DynASM.

Mike Pall il y a 14 ans
Parent
commit
3f8fed5358
2 fichiers modifiés avec 52 ajouts et 38 suppressions
  1. 14 6
      dynasm/dasm_arm.h
  2. 38 32
      dynasm/dasm_arm.lua

+ 14 - 6
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;

+ 38 - 32
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.