diff --git a/dynasm/dasm_x86.h b/dynasm/dasm_x86.h index 2e2f2334..d8d4928c 100644 --- a/dynasm/dasm_x86.h +++ b/dynasm/dasm_x86.h @@ -239,8 +239,11 @@ void dasm_put(Dst_DECL, int start, ...) } pos++; ofs += 4; /* Maximum offset needed. */ - if (action == DASM_REL_LG || action == DASM_REL_PC) + if (action == DASM_REL_LG || action == DASM_REL_PC) { b[pos++] = ofs; /* Store pass1 offset estimate. */ + } else if (sizeof(ptrdiff_t) == 8) { + ofs += 4; + } break; case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); @@ -365,10 +368,22 @@ int dasm_link(Dst_DECL, size_t *szp) do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) #define dasmd(x) \ do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) +#define dasmq(x) \ + do { *((unsigned long long *)cp) = (unsigned long long)(x); cp+=8; } while (0) #else #define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) #define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) +#define dasmq(x) do { dasmd(x); dasmd((x)>>32); } while (0) #endif +static unsigned char *dasma_(unsigned char *cp, ptrdiff_t x) +{ + if (sizeof(ptrdiff_t) == 8) + dasmq((unsigned long long)x); + else + dasmd((unsigned int)x); + return cp; +} +#define dasma(x) (cp = dasma_(cp, (x))) /* Pass 3: Encode sections. */ int dasm_encode(Dst_DECL, void *buffer) @@ -443,12 +458,13 @@ int dasm_encode(Dst_DECL, void *buffer) goto wb; } case DASM_IMM_LG: - p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } + p++; + if (n < 0) { dasma((ptrdiff_t)D->globals[-n]); break; } /* fallthrough */ case DASM_IMM_PC: { int *pb = DASM_POS2PTR(D, n); - n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); - goto wd; + dasma(*pb < 0 ? (ptrdiff_t)pb[1] : (*pb + (ptrdiff_t)base)); + break; } case DASM_LABEL_LG: { int idx = *p++; diff --git a/dynasm/dasm_x86.lua b/dynasm/dasm_x86.lua index bc9a0001..0c803dcd 100644 --- a/dynasm/dasm_x86.lua +++ b/dynasm/dasm_x86.lua @@ -484,6 +484,22 @@ local function wputdarg(n) end end +-- Put signed or unsigned qword or arg. +local function wputqarg(n) + local tn = type(n) + if tn == "number" then -- This is only used for numbers from -2^31..2^32-1. + wputb(band(n, 255)) + wputb(band(shr(n, 8), 255)) + wputb(band(shr(n, 16), 255)) + wputb(shr(n, 24)) + local sign = n < 0 and 255 or 0 + wputb(sign); wputb(sign); wputb(sign); wputb(sign) + else + waction("IMM_D", format("(unsigned int)(%s)", n)) + waction("IMM_D", format("(unsigned int)((unsigned long long)(%s)>>32)", n)) + end +end + -- Put operand-size dependent number or arg (defaults to dword). local function wputszarg(sz, n) if not sz or sz == "d" or sz == "q" then wputdarg(n) @@ -663,10 +679,16 @@ local function opmodestr(op, args) end -- Convert number to valid integer or nil. -local function toint(expr) +local function toint(expr, isqword) local n = tonumber(expr) if n then - if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then + if n % 1 ~= 0 then + werror("not an integer number `"..expr.."'") + elseif isqword then + if n < -2147483648 or n > 2147483647 then + n = nil -- Handle it as an expression to avoid precision loss. + end + elseif n < -2147483648 or n > 4294967295 then werror("bad integer number `"..expr.."'") end return n @@ -749,7 +771,7 @@ local function rtexpr(expr) end -- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }. -local function parseoperand(param) +local function parseoperand(param, isqword) local t = {} local expr = param @@ -837,7 +859,7 @@ local function parseoperand(param) t.disp = dispexpr(tailx) else -- imm or opsize*imm - local imm = toint(expr) + local imm = toint(expr, isqword) if not imm and sub(expr, 1, 1) == "*" and t.opsize then imm = toint(sub(expr, 2)) if imm then @@ -1952,7 +1974,7 @@ local function dopattern(pat, args, sz, op, needrex) local a = args[narg] narg = narg + 1 local mode, imm = a.mode, a.imm - if mode == "iJ" and not match("iIJ", c) then + if mode == "iJ" and not match(x64 and "J" or "iIJ", c) then werror("bad operand size for label") end if c == "S" then @@ -2144,14 +2166,16 @@ end local function op_data(params) if not params then return "imm..." end local sz = sub(params.op, 2, 2) - if sz == "a" then sz = addrsize end + if sz == "l" then sz = "d" elseif sz == "a" then sz = addrsize end for _,p in ipairs(params) do - local a = parseoperand(p) + local a = parseoperand(p, sz == "q") if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then werror("bad mode or size in `"..p.."'") end if a.mode == "iJ" then wputlabel("IMM_", a.imm, 1) + elseif sz == "q" then + wputqarg(a.imm) else wputszarg(sz, a.imm) end @@ -2163,7 +2187,11 @@ map_op[".byte_*"] = op_data map_op[".sbyte_*"] = op_data map_op[".word_*"] = op_data map_op[".dword_*"] = op_data +map_op[".qword_*"] = op_data map_op[".aword_*"] = op_data +map_op[".long_*"] = op_data +map_op[".quad_*"] = op_data +map_op[".addr_*"] = op_data ------------------------------------------------------------------------------