BR 2148448: Fix RIP-relative addressing with an immediate
authorH. Peter Anvin <hpa@zytor.com>
Tue, 7 Oct 2008 02:11:07 +0000 (19:11 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 7 Oct 2008 02:11:07 +0000 (19:11 -0700)
When there is an immediate in the instruction, a RIP-relative offset
may not be relative to the end of the offset itself, since it is
relative to the end of the *instruction*, not the end of the *offset*.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
assemble.c
test/riprel2.asm [new file with mode: 0644]

index d6abeac..d7e9eae 100644 (file)
@@ -796,7 +796,7 @@ static bool is_sbyte64(operand *o)
     return v >= -128 && v <= 127;
 }
 static int64_t calcsize(int32_t segment, int64_t offset, int bits,
-                     insn * ins, const uint8_t *codes)
+                       insn * ins, const uint8_t *codes)
 {
     int64_t length = 0;
     uint8_t c;
@@ -1777,6 +1777,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
                int32_t rflags;
                 uint8_t *p;
                 int32_t s;
+               enum out_type type;
 
                 if (c <= 0177) {
                    /* pick rfield from operand b */
@@ -1840,12 +1841,16 @@ static void gencode(int32_t segment, int64_t offset, int bits,
                 case 4:
                     data = ins->oprs[(c >> 3) & 7].offset;
                    warn_overflow(ea_data.bytes, opx);
-                    out(offset, segment, &data,
-                        ea_data.rip ?  OUT_REL4ADR : OUT_ADDRESS,
-                       ea_data.bytes,
-                        ins->oprs[(c >> 3) & 7].segment,
-                        ins->oprs[(c >> 3) & 7].wrt);
                     s += ea_data.bytes;
+                   if (ea_data.rip) {
+                       data -= insn_end - (offset+ea_data.bytes);
+                       type = OUT_REL4ADR;
+                   } else {
+                       type = OUT_ADDRESS;
+                   }
+                   out(offset, segment, &data, type, ea_data.bytes,
+                       ins->oprs[(c >> 3) & 7].segment,
+                       ins->oprs[(c >> 3) & 7].wrt);
                     break;
                 }
                 offset += s;
diff --git a/test/riprel2.asm b/test/riprel2.asm
new file mode 100644 (file)
index 0000000..2d13d3e
--- /dev/null
@@ -0,0 +1,11 @@
+;Testname=unoptimized; Arguments=-fbin -oriprel2.bin -O0; Files=stdout stderr riprel.bin
+;Testname=optimized;   Arguments=-fbin -oriprel2.bin -Ox; Files=stdout stderr riprel.bin
+
+       bits 64
+
+       default rel
+       mov dword [foo],12345678h
+       mov qword [foo],12345678h
+       mov [foo],rax
+       mov dword [foo],12345678h
+foo: