From 348dd9f4a68a5a6217142c64070765733af3a8c8 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Wed, 15 Nov 2017 13:39:28 +0100 Subject: [PATCH] Fix absolute memory references This properly fixes what 870271ea tried to fix. Absolute memory references can't use %rip relative addressing, and additionally, if the address doesn't fit 32bit (signed) it must be loaded via movabs. No good testcase added, it would require catching signals and still be unreliable. --- x86_64-gen.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/x86_64-gen.c b/x86_64-gen.c index 4d063cb..d7cb895 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -288,12 +288,18 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got) op_reg = REG_VALUE(op_reg) << 3; if ((r & VT_VALMASK) == VT_CONST) { /* constant memory reference */ - o(0x05 | op_reg); - if (is_got) { - gen_gotpcrel(r, sym, c); - } else { - gen_addrpc32(r, sym, c); - } + if (!(r & VT_SYM)) { + /* Absolute memory reference */ + o(0x04 | op_reg); /* [sib] | destreg */ + oad(0x25, c); /* disp32 */ + } else { + o(0x05 | op_reg); /* (%rip)+disp32 | destreg */ + if (is_got) { + gen_gotpcrel(r, sym, c); + } else { + gen_addrpc32(r, sym, c); + } + } } else if ((r & VT_VALMASK) == VT_LOCAL) { /* currently, we use only ebp as base */ if (c == (char)c) { @@ -381,6 +387,19 @@ void load(int r, SValue *sv) fr = get_reg(RC_INT); load(fr, &v1); } + if (fc != sv->c.i) { + /* If the addends doesn't fit into a 32bit signed + we must use a 64bit move. We've checked above + that this doesn't have a sym associated. */ + v1.type.t = VT_LLONG; + v1.r = VT_CONST; + v1.c.i = sv->c.i; + fr = r; + if (!(reg_classes[fr] & (RC_INT|RC_R11))) + fr = get_reg(RC_INT); + load(fr, &v1); + fc = 0; + } ll = 0; /* Like GCC we can load from small enough properly sized structs and unions as well.