Home | History | Annotate | Download | only in elf
      1 /*
      2  * ELF object format helpers - x86:amd64
      3  *
      4  *  Copyright (C) 2004-2007  Michael Urman
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <util.h>
     29 
     30 #include <libyasm.h>
     31 #define YASM_OBJFMT_ELF_INTERNAL
     32 #include "elf.h"
     33 #include "elf-machine.h"
     34 
     35 static elf_machine_ssym elf_x86_amd64_ssyms[] = {
     36     {"pltoff",      ELF_SSYM_SYM_RELATIVE,  R_X86_64_PLTOFF64,  64},
     37     {"plt",         ELF_SSYM_SYM_RELATIVE,  R_X86_64_PLT32,     32},
     38     {"gotplt",      ELF_SSYM_SYM_RELATIVE,  R_X86_64_GOTPLT64,  64},
     39     {"gotoff",      ELF_SSYM_SYM_RELATIVE,  R_X86_64_GOTOFF64,  64},
     40     {"gotpcrel",    ELF_SSYM_SYM_RELATIVE,  R_X86_64_GOTPCREL,  32},
     41     {"tlsgd",       ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     42                     R_X86_64_TLSGD,     32},
     43     {"tlsld",       ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     44                     R_X86_64_TLSLD,     32},
     45     {"gottpoff",    ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     46                     R_X86_64_GOTTPOFF,  32},
     47     {"tpoff",       ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     48                     R_X86_64_TPOFF32,   32},
     49     {"dtpoff",      ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     50                     R_X86_64_DTPOFF32,  32},
     51     {"got",         ELF_SSYM_SYM_RELATIVE,  R_X86_64_GOT32,     32},
     52     {"tlsdesc",     ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     53                     R_X86_64_GOTPC32_TLSDESC,   32},
     54     {"tlscall",     ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
     55                     R_X86_64_TLSDESC_CALL,      32}
     56 };
     57 
     58 static int
     59 elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt)
     60 {
     61     if (wrt) {
     62         const elf_machine_ssym *ssym = (elf_machine_ssym *)
     63             yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
     64         if (!ssym || val != ssym->size)
     65             return 0;
     66         return 1;
     67     }
     68     return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0);
     69 }
     70 
     71 static void
     72 elf_x86_amd64_write_symtab_entry(unsigned char *bufp,
     73                                  elf_symtab_entry *entry,
     74                                  yasm_intnum *value_intn,
     75                                  yasm_intnum *size_intn)
     76 {
     77     YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
     78     YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type));
     79     YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis));
     80     if (entry->sect) {
     81         elf_secthead *shead =
     82             yasm_section_get_data(entry->sect, &elf_section_data);
     83         if (!shead)
     84             yasm_internal_error(N_("symbol references section without data"));
     85         YASM_WRITE_16_L(bufp, shead->index);
     86     } else {
     87         YASM_WRITE_16_L(bufp, entry->index);
     88     }
     89     YASM_WRITE_64I_L(bufp, value_intn);
     90     YASM_WRITE_64I_L(bufp, size_intn);
     91 }
     92 
     93 static void
     94 elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead)
     95 {
     96     YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
     97     YASM_WRITE_32_L(bufp, shead->type);
     98     YASM_WRITE_64Z_L(bufp, shead->flags);
     99     YASM_WRITE_64Z_L(bufp, 0);          /* vmem address */
    100     YASM_WRITE_64Z_L(bufp, shead->offset);
    101     YASM_WRITE_64I_L(bufp, shead->size);
    102 
    103     YASM_WRITE_32_L(bufp, shead->link);
    104     YASM_WRITE_32_L(bufp, shead->info);
    105 
    106     YASM_WRITE_64Z_L(bufp, shead->align);
    107     YASM_WRITE_64Z_L(bufp, shead->entsize);
    108 }
    109 
    110 static void
    111 elf_x86_amd64_write_secthead_rel(unsigned char *bufp,
    112                                  elf_secthead *shead,
    113                                  elf_section_index symtab_idx,
    114                                  elf_section_index sindex)
    115 {
    116     yasm_intnum *nreloc;
    117     yasm_intnum *relocsize;
    118 
    119     YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
    120     YASM_WRITE_32_L(bufp, SHT_RELA);
    121     YASM_WRITE_64Z_L(bufp, 0);
    122     YASM_WRITE_64Z_L(bufp, 0);
    123     YASM_WRITE_64Z_L(bufp, shead->rel_offset);
    124 
    125     nreloc = yasm_intnum_create_uint(shead->nreloc);
    126     relocsize = yasm_intnum_create_uint(RELOC64A_SIZE);
    127     yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
    128     YASM_WRITE_64I_L(bufp, relocsize);          /* size */
    129     yasm_intnum_destroy(nreloc);
    130     yasm_intnum_destroy(relocsize);
    131 
    132     YASM_WRITE_32_L(bufp, symtab_idx);          /* link: symtab index */
    133     YASM_WRITE_32_L(bufp, shead->index);        /* info: relocated's index */
    134     YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN);      /* align */
    135     YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE);      /* entity size */
    136 }
    137 
    138 static void
    139 elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn,
    140                                   elf_reloc_entry *reloc,
    141                                   unsigned long offset)
    142 {
    143     /* .rela: copy value out as addend, replace original with 0 */
    144     reloc->addend = yasm_intnum_copy(intn);
    145     yasm_intnum_zero(intn);
    146 }
    147 
    148 static unsigned int
    149 elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc)
    150 {
    151     if (reloc->wrt) {
    152         const elf_machine_ssym *ssym = (elf_machine_ssym *)
    153             yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
    154         if (!ssym || reloc->valsize != ssym->size)
    155             yasm_internal_error(N_("Unsupported WRT"));
    156 
    157         /* Force TLS type; this is required by the linker. */
    158         if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
    159             elf_symtab_entry *esym;
    160 
    161             esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
    162             if (esym)
    163                 esym->type = STT_TLS;
    164         }
    165         /* Map PC-relative GOT to appropriate relocation */
    166         if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
    167             return (unsigned char) R_X86_64_GOTPCREL;
    168         return (unsigned char) ssym->reloc;
    169     } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
    170         return (unsigned char) R_X86_64_GOTPC32;
    171     } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
    172         return (unsigned char) R_X86_64_GOTPC64;
    173     } else if (reloc->rtype_rel) {
    174         switch (reloc->valsize) {
    175             case 8: return (unsigned char) R_X86_64_PC8;
    176             case 16: return (unsigned char) R_X86_64_PC16;
    177             case 32: return (unsigned char) R_X86_64_PC32;
    178             case 64: return (unsigned char) R_X86_64_PC64;
    179             default: yasm_internal_error(N_("Unsupported relocation size"));
    180         }
    181     } else {
    182         switch (reloc->valsize) {
    183             case 8: return (unsigned char) R_X86_64_8;
    184             case 16: return (unsigned char) R_X86_64_16;
    185             case 32: return (unsigned char) R_X86_64_32;
    186             case 64: return (unsigned char) R_X86_64_64;
    187             default: yasm_internal_error(N_("Unsupported relocation size"));
    188         }
    189     }
    190     return 0;
    191 }
    192 
    193 static void
    194 elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
    195                           unsigned int r_type, unsigned int r_sym)
    196 {
    197     YASM_WRITE_64I_L(bufp, reloc->reloc.addr);
    198     /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/
    199     YASM_WRITE_64C_L(bufp, r_sym, r_type);
    200     if (reloc->addend)
    201         YASM_WRITE_64I_L(bufp, reloc->addend);
    202     else {
    203         YASM_WRITE_32_L(bufp, 0);
    204         YASM_WRITE_32_L(bufp, 0);
    205     }
    206 }
    207 
    208 static void
    209 elf_x86_amd64_write_proghead(unsigned char **bufpp,
    210                              elf_offset secthead_addr,
    211                              unsigned long secthead_count,
    212                              elf_section_index shstrtab_index)
    213 {
    214     unsigned char *bufp = *bufpp;
    215     unsigned char *buf = bufp-4;
    216     YASM_WRITE_8(bufp, ELFCLASS64);         /* elf class */
    217     YASM_WRITE_8(bufp, ELFDATA2LSB);        /* data encoding :: MSB? */
    218     YASM_WRITE_8(bufp, EV_CURRENT);         /* elf version */
    219     YASM_WRITE_8(bufp, ELFOSABI_SYSV);      /* os/abi */
    220     YASM_WRITE_8(bufp, 0);                  /* SYSV v3 ABI=0 */
    221     while (bufp-buf < EI_NIDENT)            /* e_ident padding */
    222         YASM_WRITE_8(bufp, 0);
    223 
    224     YASM_WRITE_16_L(bufp, ET_REL);          /* e_type - object file */
    225     YASM_WRITE_16_L(bufp, EM_X86_64);       /* e_machine - or others */
    226     YASM_WRITE_32_L(bufp, EV_CURRENT);      /* elf version */
    227     YASM_WRITE_64Z_L(bufp, 0);              /* e_entry */
    228     YASM_WRITE_64Z_L(bufp, 0);              /* e_phoff */
    229     YASM_WRITE_64Z_L(bufp, secthead_addr);  /* e_shoff secthead off */
    230 
    231     YASM_WRITE_32_L(bufp, 0);               /* e_flags */
    232     YASM_WRITE_16_L(bufp, EHDR64_SIZE);     /* e_ehsize */
    233     YASM_WRITE_16_L(bufp, 0);               /* e_phentsize */
    234     YASM_WRITE_16_L(bufp, 0);               /* e_phnum */
    235     YASM_WRITE_16_L(bufp, SHDR64_SIZE);     /* e_shentsize */
    236     YASM_WRITE_16_L(bufp, secthead_count);  /* e_shnum */
    237     YASM_WRITE_16_L(bufp, shstrtab_index);  /* e_shstrndx */
    238     *bufpp = bufp;
    239 }
    240 
    241 const elf_machine_handler
    242 elf_machine_handler_x86_amd64 = {
    243     "x86", "amd64", ".rela",
    244     SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE,
    245     elf_x86_amd64_accepts_reloc,
    246     elf_x86_amd64_write_symtab_entry,
    247     elf_x86_amd64_write_secthead,
    248     elf_x86_amd64_write_secthead_rel,
    249     elf_x86_amd64_handle_reloc_addend,
    250     elf_x86_amd64_map_reloc_info_to_type,
    251     elf_x86_amd64_write_reloc,
    252     elf_x86_amd64_write_proghead,
    253     elf_x86_amd64_ssyms,
    254     sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]),
    255     64
    256 };
    257