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