summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-05-06 15:25:43 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2010-05-06 15:33:24 -0700
commit55ae12052cd110cc27fa8ef15a114b4e75fa4c24 (patch)
treebdb7acd17f7c4b75f2ff48e527a9d454260b35ba
parent97ec06a16a0871330d8f4544de9cd95fc88d31df (diff)
downloadnasm-55ae12052cd110cc27fa8ef15a114b4e75fa4c24.tar.gz
Add support for one-byte relocations
Add OUT_REL1ADR (one-byte relative address) and support for OUT_ADDRESs with size == 1. Add support for it in outbin and outdbg. *It still needs to be added to other backends*, both the OUT_REL*ADR and OUT_ADDRESS codepaths need to be handled. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--assemble.c16
-rw-r--r--listing.c113
-rw-r--r--nasm.h1
-rw-r--r--output/outbin.c58
-rw-r--r--output/outdbg.c4
-rw-r--r--output/outlib.c2
6 files changed, 68 insertions, 126 deletions
diff --git a/assemble.c b/assemble.c
index ca6f18f1..00ee78fb 100644
--- a/assemble.c
+++ b/assemble.c
@@ -365,23 +365,15 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
while (t--) { /* repeat TIMES times */
list_for_each(e, instruction->eops) {
if (e->type == EOT_DB_NUMBER) {
- if (wsize == 1) {
- if (e->segment != NO_SEG)
- errfunc(ERR_NONFATAL,
- "one-byte relocation attempted");
- else {
- uint8_t out_byte = e->offset;
- out(offset, segment, &out_byte,
- OUT_RAWDATA, 1, NO_SEG, NO_SEG);
- }
- } else if (wsize > 8) {
+ if (wsize > 8) {
errfunc(ERR_NONFATAL,
"integer supplied to a DT, DO or DY"
" instruction");
- } else
+ } else {
out(offset, segment, &e->offset,
OUT_ADDRESS, wsize, e->segment, e->wrt);
- offset += wsize;
+ offset += wsize;
+ }
} else if (e->type == EOT_DB_STRING ||
e->type == EOT_DB_STRING_FREE) {
int align;
diff --git a/listing.c b/listing.c
index 5a09440c..38d7908e 100644
--- a/listing.c
+++ b/listing.c
@@ -173,9 +173,30 @@ static void list_out(int32_t offset, char *str)
strcat(listdata, str);
}
+static void list_address(int32_t offset, const char *brackets,
+ int64_t addr, int size)
+{
+ char q[20];
+ char *r = q;
+
+ nasm_assert(size <= 8);
+
+ *r++ = brackets[0];
+ while (size--) {
+ HEX(r, addr);
+ addr >>= 8;
+ r += 2;
+ }
+ *r++ = brackets[1];
+ *r = '\0';
+ list_out(offset, q);
+}
+
static void list_output(int32_t offset, const void *data,
enum out_type type, uint64_t size)
{
+ char q[20];
+
if (!listp || suppress || user_nolist) /* fbk - 9/2/00 */
return;
@@ -183,7 +204,7 @@ static void list_output(int32_t offset, const void *data,
case OUT_RAWDATA:
{
uint8_t const *p = data;
- char q[3];
+
if (size == 0 && !listdata[0])
listoffset = offset;
while (size--) {
@@ -195,98 +216,22 @@ static void list_output(int32_t offset, const void *data,
break;
}
case OUT_ADDRESS:
- {
- uint64_t d = *(int64_t *)data;
- char q[20];
- uint8_t p[8], *r = p;
- if (size == 4) {
- q[0] = '[';
- q[9] = ']';
- q[10] = '\0';
- WRITELONG(r, d);
- HEX(q + 1, p[0]);
- HEX(q + 3, p[1]);
- HEX(q + 5, p[2]);
- HEX(q + 7, p[3]);
- list_out(offset, q);
- } else if (size == 8) {
- q[0] = '[';
- q[17] = ']';
- q[18] = '\0';
- WRITEDLONG(r, d);
- HEX(q + 1, p[0]);
- HEX(q + 3, p[1]);
- HEX(q + 5, p[2]);
- HEX(q + 7, p[3]);
- HEX(q + 9, p[4]);
- HEX(q + 11, p[5]);
- HEX(q + 13, p[6]);
- HEX(q + 15, p[7]);
- list_out(offset, q);
- } else {
- q[0] = '[';
- q[5] = ']';
- q[6] = '\0';
- WRITESHORT(r, d);
- HEX(q + 1, p[0]);
- HEX(q + 3, p[1]);
- list_out(offset, q);
- }
+ list_address(offset, "[]", *(int64_t *)data, size);
+ break;
+ case OUT_REL1ADR:
+ list_address(offset, "()", *(int64_t *)data, 1);
break;
- }
case OUT_REL2ADR:
- {
- uint32_t d = *(int32_t *)data;
- char q[11];
- uint8_t p[4], *r = p;
- q[0] = '(';
- q[5] = ')';
- q[6] = '\0';
- WRITESHORT(r, d);
- HEX(q + 1, p[0]);
- HEX(q + 3, p[1]);
- list_out(offset, q);
+ list_address(offset, "()", *(int64_t *)data, 2);
break;
- }
case OUT_REL4ADR:
- {
- uint32_t d = *(int32_t *)data;
- char q[11];
- uint8_t p[4], *r = p;
- q[0] = '(';
- q[9] = ')';
- q[10] = '\0';
- WRITELONG(r, d);
- HEX(q + 1, p[0]);
- HEX(q + 3, p[1]);
- HEX(q + 5, p[2]);
- HEX(q + 7, p[3]);
- list_out(offset, q);
+ list_address(offset, "()", *(int64_t *)data, 4);
break;
- }
case OUT_REL8ADR:
- {
- uint64_t d = *(int64_t *)data;
- char q[19];
- uint8_t p[8], *r = p;
- q[0] = '(';
- q[17] = ')';
- q[18] = '\0';
- WRITEDLONG(r, d);
- HEX(q + 1, p[0]);
- HEX(q + 3, p[1]);
- HEX(q + 5, p[2]);
- HEX(q + 7, p[3]);
- HEX(q + 9, p[4]);
- HEX(q + 11, p[5]);
- HEX(q + 13, p[6]);
- HEX(q + 15, p[7]);
- list_out(offset, q);
+ list_address(offset, "()", *(int64_t *)data, 8);
break;
- }
case OUT_RESERVE:
{
- char q[20];
snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
list_out(offset, q);
break;
diff --git a/nasm.h b/nasm.h
index 4bdaec8e..236f2f40 100644
--- a/nasm.h
+++ b/nasm.h
@@ -101,6 +101,7 @@ enum out_type {
OUT_RAWDATA, /* Plain bytes */
OUT_ADDRESS, /* An address (symbol value) */
OUT_RESERVE, /* Reserved bytes (RESB et al) */
+ OUT_REL1ADR, /* 1-byte relative address */
OUT_REL2ADR, /* 2-byte relative address */
OUT_REL4ADR, /* 4-byte relative address */
OUT_REL8ADR, /* 8-byte relative address */
diff --git a/output/outbin.c b/output/outbin.c
index dca7721c..70a50998 100644
--- a/output/outbin.c
+++ b/output/outbin.c
@@ -540,24 +540,13 @@ static void bin_cleanup(int debuginfo)
list_for_each(r, relocs) {
uint8_t *p, *q, mydata[8];
int64_t l;
+ int b;
saa_fread(r->target->contents, r->posn, mydata, r->bytes);
p = q = mydata;
- l = *p++;
-
- if (r->bytes > 1) {
- l += ((int64_t)*p++) << 8;
- if (r->bytes >= 4) {
- l += ((int64_t)*p++) << 16;
- l += ((int64_t)*p++) << 24;
- }
- if (r->bytes == 8) {
- l += ((int64_t)*p++) << 32;
- l += ((int64_t)*p++) << 40;
- l += ((int64_t)*p++) << 48;
- l += ((int64_t)*p++) << 56;
- }
- }
+ l = 0;
+ for (b = 0; b < r->bytes; b++)
+ l = (l << 8) + *p++;
s = find_section_by_index(r->secref);
if (s) {
@@ -574,12 +563,7 @@ static void bin_cleanup(int debuginfo)
l -= s->vstart;
}
- if (r->bytes >= 4)
- WRITEDLONG(q, l);
- else if (r->bytes == 2)
- WRITESHORT(q, l);
- else
- *q++ = (uint8_t)(l & 0xFF);
+ WRITEADDR(q, l, r->bytes);
saa_fwrite(r->target->contents, r->posn, mydata, r->bytes);
}
@@ -776,7 +760,8 @@ static void bin_out(int32_t segto, const void *data,
nasm_error(ERR_WARNING, "attempt to initialize memory in a"
" nobits section: ignored");
- if (type == OUT_ADDRESS) {
+ switch (type) {
+ case OUT_ADDRESS:
if (segment != NO_SEG && !find_section_by_index(segment)) {
if (segment % 2)
nasm_error(ERR_NONFATAL, "binary output format does not support"
@@ -793,20 +778,26 @@ static void bin_out(int32_t segto, const void *data,
WRITEADDR(p, *(int64_t *)data, size);
saa_wbytes(s->contents, mydata, size);
}
- s->length += size;
- } else if (type == OUT_RAWDATA) {
+ break;
+
+ case OUT_RAWDATA:
if (s->flags & TYPE_PROGBITS)
saa_wbytes(s->contents, data, size);
- s->length += size;
- } else if (type == OUT_RESERVE) {
+ break;
+
+ case OUT_RESERVE:
if (s->flags & TYPE_PROGBITS) {
nasm_error(ERR_WARNING, "uninitialized space declared in"
" %s section: zeroing", s->name);
saa_wbytes(s->contents, NULL, size);
}
- s->length += size;
- } else if (type == OUT_REL2ADR || type == OUT_REL4ADR ||
- type == OUT_REL8ADR) {
+ break;
+
+ case OUT_REL1ADR:
+ case OUT_REL2ADR:
+ case OUT_REL4ADR:
+ case OUT_REL8ADR:
+ {
int64_t addr = *(int64_t *)data - size;
size = realsize(type, size);
if (segment != NO_SEG && !find_section_by_index(segment)) {
@@ -824,8 +815,15 @@ static void bin_out(int32_t segto, const void *data,
WRITEADDR(p, addr - s->length, size);
saa_wbytes(s->contents, mydata, size);
}
- s->length += size;
+ break;
}
+
+ default:
+ nasm_error(ERR_NONFATAL, "unsupported relocation type %d\n", type);
+ break;
+ }
+
+ s->length += size;
}
static void bin_deflabel(char *name, int32_t segment, int64_t offset,
diff --git a/output/outdbg.c b/output/outdbg.c
index 13d53bd8..675af83e 100644
--- a/output/outdbg.c
+++ b/output/outdbg.c
@@ -147,6 +147,10 @@ static void dbg_out(int32_t segto, const void *data,
fprintf(ofile, "addr %08"PRIx32" (seg %08"PRIx32", wrt %08"PRIx32")\n", ldata,
segment, wrt);
break;
+ case OUT_REL1ADR:
+ fprintf(ofile, "rel1adr %02"PRIx8" (seg %08"PRIx32")\n",
+ (uint8_t)*(int64_t *)data, segment);
+ break;
case OUT_REL2ADR:
fprintf(ofile, "rel2adr %04"PRIx16" (seg %08"PRIx32")\n",
(uint16_t)*(int64_t *)data, segment);
diff --git a/output/outlib.c b/output/outlib.c
index 56ac6cd5..10f1bfa0 100644
--- a/output/outlib.c
+++ b/output/outlib.c
@@ -44,6 +44,8 @@
uint64_t realsize(enum out_type type, uint64_t size)
{
switch (type) {
+ case OUT_REL1ADR:
+ return 1;
case OUT_REL2ADR:
return 2;
case OUT_REL4ADR: