ELF support for 8-bit relocations
authorH. Peter Anvin <hpa@linux.intel.com>
Thu, 6 May 2010 23:14:00 +0000 (16:14 -0700)
committerH. Peter Anvin <hpa@linux.intel.com>
Thu, 6 May 2010 23:14:00 +0000 (16:14 -0700)
Support 8-bit relocations (OUT_ADDRESS and OUT_REL1ADR) in ELF.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
output/outelf32.c
output/outelf64.c

index 4d238a7..8a14af4 100644 (file)
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2010 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -715,7 +715,8 @@ static void elf_out(int32_t segto, const void *data,
 {
     struct Section *s;
     int32_t addr;
-    uint8_t mydata[4], *p;
+    uint8_t mydata[8], *p;
+    int reltype, bytes;
     int i;
     static struct symlininfo sinfo;
 
@@ -761,18 +762,24 @@ static void elf_out(int32_t segto, const void *data,
         return;
     }
 
-    if (type == OUT_RESERVE) {
+    switch (type) {
+    case OUT_RESERVE:
         if (s->type == SHT_PROGBITS) {
             nasm_error(ERR_WARNING, "uninitialized space declared in"
                   " non-BSS section `%s': zeroing", s->name);
             elf_sect_write(s, NULL, size);
         } else
             s->len += size;
-    } else if (type == OUT_RAWDATA) {
+       break;
+
+    case OUT_RAWDATA:
         if (segment != NO_SEG)
             nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
         elf_sect_write(s, data, size);
-    } else if (type == OUT_ADDRESS) {
+       break;
+
+    case OUT_ADDRESS:
+    {
         bool gnu16 = false;
         addr = *(int64_t *)data;
         if (segment != NO_SEG) {
@@ -781,11 +788,20 @@ static void elf_out(int32_t segto, const void *data,
                       " segment base references");
             } else {
                 if (wrt == NO_SEG) {
-                    if (size == 2) {
-                        gnu16 = true;
+                   switch (size) {
+                   case 1:
+                       gnu16 = true;
+                       elf_add_reloc(s, segment, R_386_8);
+                       break;
+                   case 2:
+                       gnu16 = true;
                         elf_add_reloc(s, segment, R_386_16);
-                    } else {
+                       break;
+                   case 4:
                         elf_add_reloc(s, segment, R_386_32);
+                       break;
+                   default:    /* Error issued further down */
+                       break;
                     }
                 } else if (wrt == elf_gotpc_sect + 1) {
                     /*
@@ -825,36 +841,45 @@ static void elf_out(int32_t segto, const void *data,
         p = mydata;
         if (gnu16) {
             nasm_error(ERR_WARNING | ERR_WARN_GNUELF,
-                  "16-bit relocations in ELF is a GNU extension");
-            WRITESHORT(p, addr);
-        } else {
-            if (size != 4 && segment != NO_SEG) {
-                nasm_error(ERR_NONFATAL,
-                      "Unsupported non-32-bit ELF relocation");
-            }
-            WRITELONG(p, addr);
+                  "8- or 16-bit relocations in ELF32 is a GNU extension");
+        } else if (size != 4 && segment != NO_SEG) {
+           nasm_error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation");
         }
+       WRITEADDR(p, addr, size);
         elf_sect_write(s, mydata, size);
-    } else if (type == OUT_REL2ADR) {
-        if (segment == segto)
-            nasm_error(ERR_PANIC, "intra-segment OUT_REL2ADR");
+       break;
+    }
+
+    case OUT_REL1ADR:
+       bytes = 1;
+       reltype = R_386_PC8;
+       goto rel12adr;
+    case OUT_REL2ADR:
+       bytes = 2;
+       reltype = R_386_PC16;
+       goto rel12adr;
+
+    rel12adr:
+        nasm_assert(segment != segto);
         if (segment != NO_SEG && segment % 2) {
             nasm_error(ERR_NONFATAL, "ELF format does not support"
                   " segment base references");
         } else {
             if (wrt == NO_SEG) {
                 nasm_error(ERR_WARNING | ERR_WARN_GNUELF,
-                      "16-bit relocations in ELF is a GNU extension");
-                elf_add_reloc(s, segment, R_386_PC16);
+                      "8- or 16-bit relocations in ELF is a GNU extension");
+                elf_add_reloc(s, segment, reltype);
             } else {
                 nasm_error(ERR_NONFATAL,
                       "Unsupported non-32-bit ELF relocation");
             }
         }
-        p = mydata;
+       p = mydata;
         WRITESHORT(p, *(int64_t *)data - size);
-        elf_sect_write(s, mydata, 2L);
-    } else if (type == OUT_REL4ADR) {
+        elf_sect_write(s, mydata, bytes);
+       break;
+
+    case OUT_REL4ADR:
         if (segment == segto)
             nasm_error(ERR_PANIC, "intra-segment OUT_REL4ADR");
         if (segment != NO_SEG && segment % 2) {
@@ -876,9 +901,18 @@ static void elf_out(int32_t segto, const void *data,
                 wrt = NO_SEG;   /* we can at least _try_ to continue */
             }
         }
-        p = mydata;
+       p = mydata;
         WRITELONG(p, *(int64_t *)data - size);
         elf_sect_write(s, mydata, 4L);
+       break;
+
+    case OUT_REL8ADR:
+       nasm_error(ERR_NONFATAL,
+                  "32-bit ELF format does not support 64-bit relocations");
+       p = mydata;
+       WRITEDLONG(p, 0);
+       elf_sect_write(s, mydata, 8L);
+       break;
     }
 }
 
index 47581b4..76a6464 100644 (file)
@@ -724,6 +724,7 @@ static void elf_out(int32_t segto, const void *data,
 {
     struct Section *s;
     int64_t addr, zero;
+    int reltype, bytes;
     int i;
     static struct symlininfo sinfo;
 
@@ -783,18 +784,23 @@ static void elf_out(int32_t segto, const void *data,
         return;
     }
 
-    if (type == OUT_RESERVE) {
+    switch (type) {
+    case OUT_RESERVE:
         if (s->type == SHT_PROGBITS) {
             nasm_error(ERR_WARNING, "uninitialized space declared in"
                   " non-BSS section `%s': zeroing", s->name);
             elf_sect_write(s, NULL, size);
         } else
             s->len += size;
-    } else if (type == OUT_RAWDATA) {
+       break;
+
+    case OUT_RAWDATA:
         if (segment != NO_SEG)
             nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
         elf_sect_write(s, data, size);
-    } else if (type == OUT_ADDRESS) {
+       break;
+
+    case OUT_ADDRESS:
         addr = *(int64_t *)data;
         if (segment == NO_SEG) {
             /* Do nothing */
@@ -889,10 +895,22 @@ static void elf_out(int32_t segto, const void *data,
             }
         }
         elf_sect_writeaddr(s, addr, size);
-    } else if (type == OUT_REL2ADR) {
+       break;
+
+    case OUT_REL1ADR:
+       reltype = R_X86_64_PC8;
+       bytes = 1;
+       goto rel12adr;
+
+    case OUT_REL2ADR:
+       reltype = R_X86_64_PC16;
+       bytes = 2;
+       goto rel12adr;
+
+    rel12adr:
         addr = *(int64_t *)data - size;
         if (segment == segto)
-            nasm_error(ERR_PANIC, "intra-segment OUT_REL2ADR");
+            nasm_error(ERR_PANIC, "intra-segment OUT_REL1ADR");
         if (segment == NO_SEG) {
             /* Do nothing */
         } else if (segment % 2) {
@@ -900,15 +918,17 @@ static void elf_out(int32_t segto, const void *data,
                   " segment base references");
         } else {
             if (wrt == NO_SEG) {
-                elf_add_reloc(s, segment, addr, R_X86_64_PC16);
+                elf_add_reloc(s, segment, addr, reltype);
                 addr = 0;
             } else {
                 nasm_error(ERR_NONFATAL,
-                      "Unsupported non-32-bit ELF relocation [2]");
+                      "Unsupported non-32-bit ELF relocation");
             }
         }
-        elf_sect_writeaddr(s, addr, 2);
-    } else if (type == OUT_REL4ADR) {
+        elf_sect_writeaddr(s, addr, bytes);
+       break;
+
+    case OUT_REL4ADR:
         addr = *(int64_t *)data - size;
         if (segment == segto)
             nasm_error(ERR_PANIC, "intra-segment OUT_REL4ADR");
@@ -944,7 +964,9 @@ static void elf_out(int32_t segto, const void *data,
             }
         }
         elf_sect_writeaddr(s, addr, 4);
-    } else if (type == OUT_REL8ADR) {
+       break;
+
+    case OUT_REL8ADR:
         addr = *(int64_t *)data - size;
         if (segment == segto)
             nasm_error(ERR_PANIC, "intra-segment OUT_REL8ADR");
@@ -975,6 +997,7 @@ static void elf_out(int32_t segto, const void *data,
             }
         }
         elf_sect_writeaddr(s, addr, 8);
+       break;
     }
 }