Add support for one-byte relocations
authorH. Peter Anvin <hpa@linux.intel.com>
Thu, 6 May 2010 22:25:43 +0000 (15:25 -0700)
committerH. Peter Anvin <hpa@linux.intel.com>
Thu, 6 May 2010 22:33:24 +0000 (15:33 -0700)
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>
assemble.c
listing.c
nasm.h
output/outbin.c
output/outdbg.c
output/outlib.c

index ca6f18f..00ee78f 100644 (file)
@@ -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;
index 5a09440..38d7908 100644 (file)
--- 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 4bdaec8..236f2f4 100644 (file)
--- 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 */
index dca7721..70a5099 100644 (file)
@@ -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,
index 13d53bd..675af83 100644 (file)
@@ -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);
index 56ac6cd..10f1bfa 100644 (file)
@@ -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: