summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2013-11-26 18:23:20 -0800
committerH. Peter Anvin <hpa@zytor.com>2013-11-26 18:23:20 -0800
commit89a2ac0d0aabb586f0f6f051a721a1f2256c7492 (patch)
treea3b23d01ff3e7913369a52b7821a85beaba58e1e
parentd35f23011334d0693b48f16757e3971069ad7328 (diff)
downloadnasm-89a2ac0d0aabb586f0f6f051a721a1f2256c7492.tar.gz
assemble: Emit signed relocations where appropriate
Emit signed relocations where we know they are necessary. This is not at all exhaustive; in particular we are missing this for a number of 8- and 16-bit cases, and probably others. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--assemble.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/assemble.c b/assemble.c
index 193c4872..52a352fa 100644
--- a/assemble.c
+++ b/assemble.c
@@ -173,6 +173,7 @@
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <inttypes.h>
#include "nasm.h"
@@ -316,7 +317,8 @@ static void out(int64_t offset, int32_t segto, const void *data,
* convert it into RAWDATA format.
*/
uint8_t *q = p;
-
+
+ size = abs((int)size);
if (size > 8) {
errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
return;
@@ -344,11 +346,12 @@ static void out(int64_t offset, int32_t segto, const void *data,
outfmt->output(segto, data, type, size, segment, wrt);
}
-static void out_imm8(int64_t offset, int32_t segment, struct operand *opx)
+static void out_imm8(int64_t offset, int32_t segment,
+ struct operand *opx, int asize)
{
if (opx->segment != NO_SEG) {
uint64_t data = opx->offset;
- out(offset, segment, &data, OUT_ADDRESS, 1, opx->segment, opx->wrt);
+ out(offset, segment, &data, OUT_ADDRESS, asize, opx->segment, opx->wrt);
} else {
uint8_t byte = opx->offset;
out(offset, segment, &byte, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
@@ -1399,7 +1402,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
"byte value exceeds bounds");
}
- out_imm8(offset, segment, opx);
+ out_imm8(offset, segment, opx, -1);
offset += 1;
break;
@@ -1407,7 +1410,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
if (opx->offset < 0 || opx->offset > 255)
errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
"unsigned byte value exceeds bounds");
- out_imm8(offset, segment, opx);
+ out_imm8(offset, segment, opx, 1);
offset += 1;
break;
@@ -1570,7 +1573,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
"signed dword immediate exceeds bounds");
}
- out(offset, segment, &data, OUT_ADDRESS, 4,
+ out(offset, segment, &data, OUT_ADDRESS, -4,
opx->segment, opx->wrt);
offset += 4;
break;
@@ -1865,7 +1868,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
ea_data.bytes, NO_SEG, NO_SEG);
} else {
/* overflow check in output/linker? */
- out(offset, segment, &data, OUT_REL4ADR,
+ out(offset, segment, &data, OUT_REL4ADR,
insn_end - offset, opy->segment, opy->wrt);
}
} else {
@@ -1875,7 +1878,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
warn_overflow(ERR_PASS2, ea_data.bytes);
out(offset, segment, &data, OUT_ADDRESS,
- ea_data.bytes, opy->segment, opy->wrt);
+ -ea_data.bytes, opy->segment, opy->wrt);
}
break;
default: