Merge [1878] from trunk: Fix bin objfmt handling of cross-section
RIP-relative values.

svn path=/branches/yasm-0.6.x/; revision=1879
diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c
index cdbefe2..885d36c 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