]> granicus.if.org Git - yasm/commitdiff
Add rudimentary, untested, AMD64 support.
authorPeter Johnson <peter@tortall.net>
Sun, 11 Apr 2004 23:25:17 +0000 (23:25 -0000)
committerPeter Johnson <peter@tortall.net>
Sun, 11 Apr 2004 23:25:17 +0000 (23:25 -0000)
The AMD64 MASM likes to generate REL32 relocations for everything; I've not
yet figured out how this works.
This code should work fine for files without relocation.

Bugzilla bug: 33
Reported by: Jeff Lawson <jlawson-yasm@bovine.net>

svn path=/trunk/yasm/; revision=1113

modules/objfmts/coff/coff-objfmt.c

index 9963ef8e8f3b701907f2e9c1c5cdd940516240b8..c6e04f1d529f5f354b43edeb3d99a4c4a5bed6d5 100644 (file)
@@ -44,7 +44,8 @@
  */
 #define COFF_SET_VMA   (!objfmt_coff->win32)
 
-#define COFF_I386MAGIC 0x14C
+#define COFF_MACHINE_I386      0x014C
+#define COFF_MACHINE_AMD64     0x8664
 
 #define COFF_F_LNNO    0x0004      /* line number info NOT present */
 #define COFF_F_LSYMS   0x0008      /* local symbols NOT present */
@@ -57,8 +58,34 @@ typedef struct coff_reloc {
     unsigned long addr;                    /* address of relocation */
     yasm_symrec *sym;              /* relocated symbol */
     enum {
-       COFF_RELOC_ADDR32 = 6,      /* 32-bit absolute reference */
-       COFF_RELOC_REL32 = 20       /* 32-bit relative reference */
+       COFF_RELOC_ABSOLUTE = 0,            /* absolute, no reloc needed */
+
+       /* I386 relocations */
+       COFF_RELOC_I386_ADDR16 = 0x1,       /* 16-bit absolute reference */
+       COFF_RELOC_I386_REL16 = 0x2,        /* 16-bit PC-relative reference */
+       COFF_RELOC_I386_ADDR32 = 0x6,       /* 32-bit absolute reference */
+       COFF_RELOC_I386_ADDR32NB = 0x7,     /* 32-bit absolute ref w/o base */
+       COFF_RELOC_I386_SEG12 = 0x9,        /* 16-bit absolute segment ref */
+       COFF_RELOC_I386_SECTION = 0xA,      /* section index */
+       COFF_RELOC_I386_SECREL = 0xB,       /* offset from start of segment */
+       COFF_RELOC_I386_TOKEN = 0xC,        /* CLR metadata token */
+       COFF_RELOC_I386_SECREL7 = 0xD,  /* 7-bit offset from base of sect */
+       COFF_RELOC_I386_REL32 = 0x14,       /* 32-bit PC-relative reference */
+
+       /* AMD64 relocations */
+       COFF_RELOC_AMD64_ADDR64 = 0x1,      /* 64-bit address (VA) */
+       COFF_RELOC_AMD64_ADDR32 = 0x2,      /* 32-bit address (VA) */
+       COFF_RELOC_AMD64_ADDR32NB = 0x3,    /* 32-bit address w/o base (RVA) */
+       COFF_RELOC_AMD64_REL32 = 0x4,       /* 32-bit relative (0 byte dist) */
+       COFF_RELOC_AMD64_REL32_1 = 0x5,     /* 32-bit relative (1 byte dist) */
+       COFF_RELOC_AMD64_REL32_2 = 0x6,     /* 32-bit relative (2 byte dist) */
+       COFF_RELOC_AMD64_REL32_3 = 0x7,     /* 32-bit relative (3 byte dist) */
+       COFF_RELOC_AMD64_REL32_4 = 0x8,     /* 32-bit relative (4 byte dist) */
+       COFF_RELOC_AMD64_REL32_5 = 0x9,     /* 32-bit relative (5 byte dist) */
+       COFF_RELOC_AMD64_SECTION = 0xA,     /* section index */
+       COFF_RELOC_AMD64_SECREL = 0xB,  /* 32-bit offset from base of sect */
+       COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
+       COFF_RELOC_AMD64_TOKEN = 0xD        /* CLR metadata token */
     } type;                        /* type of relocation */
 } coff_reloc;
 
@@ -155,6 +182,8 @@ typedef struct yasm_objfmt_coff {
     coff_symtab_head coff_symtab;          /* symbol table of indexed syms */
     int win32;                             /* nonzero for win32 output */
 
+    unsigned int machine;                  /* COFF machine to use */
+
     yasm_object *object;
     yasm_symtab *symtab;
     /*@dependent@*/ yasm_arch *arch;
@@ -244,9 +273,18 @@ coff_common_create(const char *in_filename, yasm_object *object, yasm_arch *a)
     objfmt_coff->symtab = yasm_object_get_symtab(object);
     objfmt_coff->arch = a;
 
-    /* Only support x86 arch, x86 machine */
-    if (yasm__strcasecmp(yasm_arch_keyword(a), "x86") != 0 ||
-       yasm__strcasecmp(yasm_arch_get_machine(a), "x86") != 0) {
+    /* Only support x86 arch */
+    if (yasm__strcasecmp(yasm_arch_keyword(a), "x86") != 0) {
+       yasm_xfree(objfmt_coff);
+       return NULL;
+    }
+
+    /* Support x86 and amd64 machines of x86 arch */
+    if (yasm__strcasecmp(yasm_arch_get_machine(a), "x86") == 0) {
+       objfmt_coff->machine = COFF_MACHINE_I386;
+    } else if (yasm__strcasecmp(yasm_arch_get_machine(a), "amd64") == 0) {
+       objfmt_coff->machine = COFF_MACHINE_AMD64;
+    } else {
        yasm_xfree(objfmt_coff);
        return NULL;
     }
@@ -395,7 +433,12 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
        }
 
        if (rel) {
-           reloc->type = COFF_RELOC_REL32;
+           if (objfmt_coff->machine == COFF_MACHINE_I386)
+               reloc->type = COFF_RELOC_I386_REL32;
+           else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+               reloc->type = COFF_RELOC_AMD64_REL32;
+           else
+               yasm_internal_error(N_("coff objfmt: unrecognized machine"));
            /* For standard COFF, need to reference to start of section, so add
             * $$ in.
             * For Win32 COFF, need to reference to next bytecode, so add '$'
@@ -412,8 +455,14 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
                        yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
                    (*ep)->line);
            *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
-       } else
-           reloc->type = COFF_RELOC_ADDR32;
+       } else {
+           if (objfmt_coff->machine == COFF_MACHINE_I386)
+               reloc->type = COFF_RELOC_I386_ADDR32;
+           else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+               reloc->type = COFF_RELOC_AMD64_ADDR32;
+           else
+               yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+       }
        info->csd->nreloc++;
        STAILQ_INSERT_TAIL(&info->csd->relocs, reloc, link);
     }
@@ -825,7 +874,7 @@ coff_objfmt_output(yasm_objfmt *objfmt, FILE *f, const char *obj_filename,
     }
 
     localbuf = info.buf;
-    YASM_WRITE_16_L(localbuf, COFF_I386MAGIC);         /* magic number */
+    YASM_WRITE_16_L(localbuf, objfmt_coff->machine);   /* magic number */
     YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
     YASM_WRITE_32_L(localbuf, 0);                      /* time/date stamp */
     YASM_WRITE_32_L(localbuf, symtab_pos);             /* file ptr to symtab */
@@ -1117,11 +1166,20 @@ coff_section_data_print(void *data, FILE *f, int indent_level)
        yasm_symrec_print(reloc->sym, f, indent_level+3);
        fprintf(f, "%*stype=", indent_level+2, "");
        switch (reloc->type) {
-           case COFF_RELOC_ADDR32:
-               printf("Addr32\n");
+           case COFF_RELOC_I386_ADDR32:
+               printf("I386/Addr32\n");
+               break;
+           case COFF_RELOC_I386_REL32:
+               printf("I386/Rel32\n");
+               break;
+           case COFF_RELOC_AMD64_ADDR32:
+               printf("AMD64/Addr32\n");
+               break;
+           case COFF_RELOC_AMD64_REL32:
+               printf("AMD64/Rel32\n");
                break;
-           case COFF_RELOC_REL32:
-               printf("Rel32\n");
+           default:
+               printf("Other\n");
                break;
        }
     }