summaryrefslogtreecommitdiff
path: root/libyasm/value.c
diff options
context:
space:
mode:
authorPeter Johnson <peter@tortall.net>2006-09-29 07:18:45 +0000
committerPeter Johnson <peter@tortall.net>2006-09-29 07:18:45 +0000
commit3e8d2c2e7a162cc7a8d20f07e60f6f009914e795 (patch)
treeb2ebe82cdff8684829f809d3fd73633eedf29e88 /libyasm/value.c
parent096e2eb79a83c8da2d9e7f4841c2cb853be5befc (diff)
downloadyasm-3e8d2c2e7a162cc7a8d20f07e60f6f009914e795.tar.gz
- Fix much brokenness in absolute value handling, particularly in regards to
PC-relative relocations (jumps and calls). - Allow SEG:OFF to be used as just an offset portion (like NASM does). - Labels in absolute sections that are declared global are given the correct absolute value in the symbol table. One difference from NASM: label equ 0040h:001eh jmp label in NASM means the same as: jmp 001eh (a near jump) but yasm will treat this the same as: jmp 0040h:001eh (a far jump) I'm still not completely happy with this implementation, but it's workable and fixes all the bugs I've found so far in absolute handling. svn path=/trunk/yasm/; revision=1634
Diffstat (limited to 'libyasm/value.c')
-rw-r--r--libyasm/value.c40
1 files changed, 38 insertions, 2 deletions
diff --git a/libyasm/value.c b/libyasm/value.c
index 50b5482c..6ef16855 100644
--- a/libyasm/value.c
+++ b/libyasm/value.c
@@ -98,6 +98,22 @@ yasm_value_delete(yasm_value *value)
value->rel = NULL;
}
+void
+yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
+ unsigned int ip_rel)
+{
+ value->curpos_rel = 1;
+ value->ip_rel = ip_rel;
+ /* In order for us to correctly output curpos-relative values, we must
+ * have a relative portion of the value. If one doesn't exist, point
+ * to a custom absolute symbol.
+ */
+ if (!value->rel) {
+ value->rel = yasm_symtab_abs_sym(yasm_object_get_symtab(
+ yasm_section_get_object(yasm_bc_get_section(bc))));
+ }
+}
+
static int
value_finalize_scan(yasm_value *value, yasm_expr *e, int ssym_not_ok)
{
@@ -569,9 +585,22 @@ yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
return -1;
}
- /* Handle integer expressions */
+ /* Handle normal integer expressions */
intn = yasm_expr_get_intnum(&value->abs, 1);
+
if (!intn) {
+ /* Second try before erroring: yasm_expr_get_intnum doesn't handle
+ * SEG:OFF, so try simplifying out any to just the OFF portion,
+ * then getting the intnum again.
+ */
+ yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
+ if (seg)
+ yasm_expr_destroy(seg);
+ intn = yasm_expr_get_intnum(&value->abs, 1);
+ }
+
+ if (!intn) {
+ /* Still don't have an integer! */
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
N_("expression too complex"));
return -1;
@@ -617,7 +646,14 @@ yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
bc, warn))
retval = -1;
yasm_intnum_destroy(outval);
- } else if (intn) {
+ return retval;
+ }
+
+ if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
+ || value->section_rel)
+ return 0; /* We can't handle this with just an absolute */
+
+ if (intn) {
/* Output just absolute portion */
if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
warn))