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