Fix bin objfmt handling of cross-section RIP-relative values; also clean
up absolute value handling.

svn path=/trunk/yasm/; revision=1878
diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c
index 1a0c9ec..2e7fd72 100644
--- a/modules/objfmts/bin/bin-objfmt.c
+++ b/modules/objfmts/bin/bin-objfmt.c
@@ -103,11 +103,13 @@
     /*@null@*/ yasm_intnum *dist;
 
     for (i=0; i<e->numterms; i++) {
-        /* Transform symrecs that reference sections into
+        /* Transform symrecs or precbcs that reference sections into
          * start expr + intnum(dist).
          */
-        if (e->terms[i].type == YASM_EXPR_SYM &&
-            yasm_symrec_get_label(e->terms[i].data.sym, &precbc) &&
+        if (((e->terms[i].type == YASM_EXPR_SYM &&
+             yasm_symrec_get_label(e->terms[i].data.sym, &precbc)) ||
+            (e->terms[i].type == YASM_EXPR_PRECBC &&
+             (precbc = e->terms[i].data.precbc))) &&
             (sect = yasm_bc_get_section(precbc)) &&
             (dist = yasm_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) {
             const yasm_expr *start = yasm_section_get_start(sect);
@@ -135,17 +137,36 @@
     assert(info != NULL);
 
     /* Binary objects we need to resolve against object, not against section. */
-    if (value->rel && !value->curpos_rel
-        && yasm_symrec_get_label(value->rel, &precbc)
-        && (sect = yasm_bc_get_section(precbc))) {
+    if (value->rel) {
         unsigned int rshift = (unsigned int)value->rshift;
         yasm_expr *syme;
-        if (value->rshift > 0)
-            syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_sym(value->rel),
-                yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line);
-        else
-            syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line);
 
+        if (yasm_symrec_is_abs(value->rel)) {
+            syme = yasm_expr_create_ident(yasm_expr_int(
+                yasm_intnum_create_uint(0)), bc->line);
+        } else if (yasm_symrec_get_label(value->rel, &precbc)
+                   && (sect = yasm_bc_get_section(precbc))) {
+            syme = yasm_expr_create_ident(yasm_expr_sym(value->rel), bc->line);
+        } else
+            goto done;
+
+        /* Handle PC-relative */
+        if (value->curpos_rel) {
+            yasm_expr *sube;
+            sube = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_precbc(bc),
+                yasm_expr_int(yasm_intnum_create_uint(bc->len*bc->mult_int)),
+                bc->line);
+            syme = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(syme),
+                                    yasm_expr_expr(sube), bc->line);
+            value->curpos_rel = 0;
+            value->ip_rel = 0;
+        } else
+
+        if (value->rshift > 0)
+            syme = yasm_expr_create(YASM_EXPR_SHR, yasm_expr_expr(syme),
+                yasm_expr_int(yasm_intnum_create_uint(rshift)), bc->line);
+
+        /* Add into absolute portion */
         if (!value->abs)
             value->abs = syme;
         else
@@ -155,7 +176,7 @@
         value->rel = NULL;
         value->rshift = 0;
     }
-
+done:
     /* Simplify absolute portion of value, transforming symrecs */
     if (value->abs)
         value->abs = yasm_expr__level_tree
@@ -172,36 +193,6 @@
             return 0;
     }
 
-    /* Absolute value; handle it here as output_basic won't understand it */
-    if (value->rel && yasm_symrec_is_abs(value->rel)) {
-        if (value->curpos_rel) {
-            /* Calculate value relative to current assembly position */
-            /*@only@*/ yasm_intnum *outval;
-            unsigned int valsize = value->size;
-            int retval = 0;
-
-            outval = yasm_intnum_create_uint(bc->offset + info->abs_start);
-            yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
-
-            if (value->rshift > 0) {
-                /*@only@*/ yasm_intnum *shamt =
-                    yasm_intnum_create_uint((unsigned long)value->rshift);
-                yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
-                yasm_intnum_destroy(shamt);
-            }
-            /* Add in absolute portion */
-            if (value->abs)
-                yasm_intnum_calc(outval, YASM_EXPR_ADD,
-                                 yasm_expr_get_intnum(&value->abs, 1));
-            /* Output! */
-            if (yasm_arch_intnum_tobytes(info->object->arch, outval, buf,
-                                         destsize, valsize, 0, bc, warn))
-                retval = 1;
-            yasm_intnum_destroy(outval);
-            return retval;
-        }
-    }
-
     /* Couldn't output, assume it contains an external reference. */
     yasm_error_set(YASM_ERROR_GENERAL,
         N_("binary object format does not support external references"));
diff --git a/modules/objfmts/bin/tests/Makefile.inc b/modules/objfmts/bin/tests/Makefile.inc
index 70070b0..e1993ea 100644
--- a/modules/objfmts/bin/tests/Makefile.inc
+++ b/modules/objfmts/bin/tests/Makefile.inc
@@ -10,6 +10,8 @@
 EXTRA_DIST += modules/objfmts/bin/tests/bigorg.errwarn
 EXTRA_DIST += modules/objfmts/bin/tests/bin-farabs.asm
 EXTRA_DIST += modules/objfmts/bin/tests/bin-farabs.hex
+EXTRA_DIST += modules/objfmts/bin/tests/bin-rip.asm
+EXTRA_DIST += modules/objfmts/bin/tests/bin-rip.hex
 EXTRA_DIST += modules/objfmts/bin/tests/bintest.asm
 EXTRA_DIST += modules/objfmts/bin/tests/bintest.hex
 EXTRA_DIST += modules/objfmts/bin/tests/float-err.asm
diff --git a/modules/objfmts/bin/tests/bin-rip.asm b/modules/objfmts/bin/tests/bin-rip.asm
new file mode 100755
index 0000000..2211054
--- /dev/null
+++ b/modules/objfmts/bin/tests/bin-rip.asm
@@ -0,0 +1,20 @@
+bits 64
+org 0x100
+foo_equ equ 0x12345678
+
+section .text
+nop
+foo_text:
+nop
+mov rax,[foo_equ wrt rip]
+mov rax,[foo_text wrt rip]
+mov rax,[foo_data wrt rip]
+mov rbx,[foo_equ wrt rip]
+mov rbx,[foo_text wrt rip]
+mov rbx,[foo_data wrt rip]
+
+section .data
+db 0
+foo_data:
+db 0
+
diff --git a/modules/objfmts/bin/tests/bin-rip.hex b/modules/objfmts/bin/tests/bin-rip.hex
new file mode 100644
index 0000000..d56601d
--- /dev/null
+++ b/modules/objfmts/bin/tests/bin-rip.hex
@@ -0,0 +1,46 @@
+90 
+90 
+48 
+8b 
+05 
+6f 
+55 
+34 
+12 
+48 
+8b 
+05 
+f1 
+ff 
+ff 
+ff 
+48 
+8b 
+05 
+16 
+00 
+00 
+00 
+48 
+8b 
+1d 
+5a 
+55 
+34 
+12 
+48 
+8b 
+1d 
+dc 
+ff 
+ff 
+ff 
+48 
+8b 
+1d 
+01 
+00 
+00 
+00 
+00 
+00