|
@@ -23,12 +23,12 @@ local _M = { _info = _info }
|
|
|
local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
|
|
|
local assert, setmetatable, rawget = assert, setmetatable, rawget
|
|
|
local _s = string
|
|
|
-local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
|
|
|
+local format, byte, char = _s.format, _s.byte, _s.char
|
|
|
local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
|
|
|
local concat, sort, insert = table.concat, table.sort, table.insert
|
|
|
local bit = bit or require("bit")
|
|
|
local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
|
|
|
-local ror, tohex = bit.ror, bit.tohex
|
|
|
+local ror, tohex, tobit = bit.ror, bit.tohex, bit.tobit
|
|
|
|
|
|
-- Inherited tables and callbacks.
|
|
|
local g_opt, g_arch
|
|
@@ -39,7 +39,8 @@ local wline, werror, wfatal, wwarn
|
|
|
local action_names = {
|
|
|
"STOP", "SECTION", "ESC", "REL_EXT",
|
|
|
"ALIGN", "REL_LG", "LABEL_LG",
|
|
|
- "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML",
|
|
|
+ "REL_PC", "LABEL_PC", "REL_A",
|
|
|
+ "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", "IMMV",
|
|
|
"VREG",
|
|
|
}
|
|
|
|
|
@@ -311,7 +312,7 @@ local function parse_number(n)
|
|
|
local code = loadenv("return "..n)
|
|
|
if code then
|
|
|
local ok, y = pcall(code)
|
|
|
- if ok then return y end
|
|
|
+ if ok and type(y) == "number" then return y end
|
|
|
end
|
|
|
return nil
|
|
|
end
|
|
@@ -575,14 +576,14 @@ local function parse_load_pair(params, nparams, n, op)
|
|
|
end
|
|
|
|
|
|
local function parse_label(label, def)
|
|
|
- local prefix = sub(label, 1, 2)
|
|
|
+ local prefix = label:sub(1, 2)
|
|
|
-- =>label (pc label reference)
|
|
|
if prefix == "=>" then
|
|
|
- return "PC", 0, sub(label, 3)
|
|
|
+ return "PC", 0, label:sub(3)
|
|
|
end
|
|
|
-- ->name (global label reference)
|
|
|
if prefix == "->" then
|
|
|
- return "LG", map_global[sub(label, 3)]
|
|
|
+ return "LG", map_global[label:sub(3)]
|
|
|
end
|
|
|
if def then
|
|
|
-- [1-9] (local label definition)
|
|
@@ -600,8 +601,11 @@ local function parse_label(label, def)
|
|
|
if extname then
|
|
|
return "EXT", map_extern[extname]
|
|
|
end
|
|
|
+ -- &expr (pointer)
|
|
|
+ if label:sub(1, 1) == "&" then
|
|
|
+ return "A", 0, format("(ptrdiff_t)(%s)", label:sub(2))
|
|
|
+ end
|
|
|
end
|
|
|
- werror("bad label `"..label.."'")
|
|
|
end
|
|
|
|
|
|
local function branch_type(op)
|
|
@@ -895,14 +899,14 @@ end
|
|
|
|
|
|
-- Handle opcodes defined with template strings.
|
|
|
local function parse_template(params, template, nparams, pos)
|
|
|
- local op = tonumber(sub(template, 1, 8), 16)
|
|
|
+ local op = tonumber(template:sub(1, 8), 16)
|
|
|
local n = 1
|
|
|
local rtt = {}
|
|
|
|
|
|
parse_reg_type = false
|
|
|
|
|
|
-- Process each character.
|
|
|
- for p in gmatch(sub(template, 9), ".") do
|
|
|
+ for p in gmatch(template:sub(9), ".") do
|
|
|
local q = params[n]
|
|
|
if p == "D" then
|
|
|
op = op + parse_reg(q, 0); n = n + 1
|
|
@@ -944,8 +948,14 @@ local function parse_template(params, template, nparams, pos)
|
|
|
|
|
|
elseif p == "B" then
|
|
|
local mode, v, s = parse_label(q, false); n = n + 1
|
|
|
+ if not mode then werror("bad label `"..q.."'") end
|
|
|
local m = branch_type(op)
|
|
|
- waction("REL_"..mode, v+m, s, 1)
|
|
|
+ if mode == "A" then
|
|
|
+ waction("REL_"..mode, v+m, format("(unsigned int)(%s)", s))
|
|
|
+ actargs[#actargs+1] = format("(unsigned int)((%s)>>32)", s)
|
|
|
+ else
|
|
|
+ waction("REL_"..mode, v+m, s, 1)
|
|
|
+ end
|
|
|
|
|
|
elseif p == "I" then
|
|
|
op = op + parse_imm12(q); n = n + 1
|
|
@@ -1050,23 +1060,50 @@ map_op[".label_1"] = function(params)
|
|
|
if not params then return "[1-9] | ->global | =>pcexpr" end
|
|
|
if secpos+1 > maxsecpos then wflush() end
|
|
|
local mode, n, s = parse_label(params[1], true)
|
|
|
- if mode == "EXT" then werror("bad label definition") end
|
|
|
+ if not mode or mode == "EXT" then werror("bad label definition") end
|
|
|
waction("LABEL_"..mode, n, s, 1)
|
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
|
|
-- Pseudo-opcodes for data storage.
|
|
|
-map_op[".long_*"] = function(params)
|
|
|
+local function op_data(params)
|
|
|
if not params then return "imm..." end
|
|
|
+ local sz = params.op == ".long" and 4 or 8
|
|
|
for _,p in ipairs(params) do
|
|
|
- local n = tonumber(p)
|
|
|
- if not n then werror("bad immediate `"..p.."'") end
|
|
|
- if n < 0 then n = n + 2^32 end
|
|
|
- wputw(n)
|
|
|
+ local imm = parse_number(p)
|
|
|
+ if imm then
|
|
|
+ local n = tobit(imm)
|
|
|
+ if n == imm or (n < 0 and n + 2^32 == imm) then
|
|
|
+ wputw(n < 0 and n + 2^32 or n)
|
|
|
+ if sz == 8 then
|
|
|
+ wputw(imm < 0 and 0xffffffff or 0)
|
|
|
+ end
|
|
|
+ elseif sz == 4 then
|
|
|
+ werror("bad immediate `"..p.."'")
|
|
|
+ else
|
|
|
+ imm = nil
|
|
|
+ end
|
|
|
+ end
|
|
|
+ if not imm then
|
|
|
+ local mode, v, s = parse_label(p, false)
|
|
|
+ if sz == 4 then
|
|
|
+ if mode then werror("label does not fit into .long") end
|
|
|
+ waction("IMMV", 0, p)
|
|
|
+ elseif mode and mode ~= "A" then
|
|
|
+ waction("REL_"..mode, v+0x8000, s, 1)
|
|
|
+ else
|
|
|
+ if mode == "A" then p = s end
|
|
|
+ waction("IMMV", 0, format("(unsigned int)(%s)", p))
|
|
|
+ waction("IMMV", 0, format("(unsigned int)((unsigned long long)(%s)>>32)", p))
|
|
|
+ end
|
|
|
+ end
|
|
|
if secpos+2 > maxsecpos then wflush() end
|
|
|
end
|
|
|
end
|
|
|
+map_op[".long_*"] = op_data
|
|
|
+map_op[".quad_*"] = op_data
|
|
|
+map_op[".addr_*"] = op_data
|
|
|
|
|
|
-- Alignment pseudo-opcode.
|
|
|
map_op[".align_1"] = function(params)
|