1 /* 2 * ELF object format helpers - x86:x86 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_x86_ssyms[] = { 36 {"plt", ELF_SSYM_SYM_RELATIVE, R_386_PLT32, 32}, 37 {"gotoff", 0, R_386_GOTOFF, 32}, 38 /* special one for NASM */ 39 {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32}, 40 {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 41 R_386_TLS_GD, 32}, 42 {"tlsldm", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 43 R_386_TLS_LDM, 32}, 44 {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 45 R_386_TLS_IE_32, 32}, 46 {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 47 R_386_TLS_LE_32, 32}, 48 {"ntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 49 R_386_TLS_LE, 32}, 50 {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 51 R_386_TLS_LDO_32, 32}, 52 {"gotntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 53 R_386_TLS_GOTIE, 32}, 54 {"indntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 55 R_386_TLS_IE, 32}, 56 {"got", ELF_SSYM_SYM_RELATIVE, R_386_GOT32, 32}, 57 {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 58 R_386_TLS_GOTDESC, 32}, 59 {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, 60 R_386_TLS_DESC_CALL, 32} 61 }; 62 63 static int 64 elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt) 65 { 66 if (wrt) { 67 const elf_machine_ssym *ssym = (elf_machine_ssym *) 68 yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); 69 if (!ssym || val != ssym->size) 70 return 0; 71 return 1; 72 } 73 return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); 74 } 75 76 static void 77 elf_x86_x86_write_symtab_entry(unsigned char *bufp, 78 elf_symtab_entry *entry, 79 yasm_intnum *value_intn, 80 yasm_intnum *size_intn) 81 { 82 YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); 83 YASM_WRITE_32I_L(bufp, value_intn); 84 YASM_WRITE_32I_L(bufp, size_intn); 85 86 YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); 87 YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); 88 if (entry->sect) { 89 elf_secthead *shead = 90 yasm_section_get_data(entry->sect, &elf_section_data); 91 if (!shead) 92 yasm_internal_error(N_("symbol references section without data")); 93 YASM_WRITE_16_L(bufp, shead->index); 94 } else { 95 YASM_WRITE_16_L(bufp, entry->index); 96 } 97 } 98 99 static void 100 elf_x86_x86_write_secthead(unsigned char *bufp, elf_secthead *shead) 101 { 102 YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); 103 YASM_WRITE_32_L(bufp, shead->type); 104 YASM_WRITE_32_L(bufp, shead->flags); 105 YASM_WRITE_32_L(bufp, 0); /* vmem address */ 106 107 YASM_WRITE_32_L(bufp, shead->offset); 108 YASM_WRITE_32I_L(bufp, shead->size); 109 YASM_WRITE_32_L(bufp, shead->link); 110 YASM_WRITE_32_L(bufp, shead->info); 111 112 YASM_WRITE_32_L(bufp, shead->align); 113 YASM_WRITE_32_L(bufp, shead->entsize); 114 115 } 116 117 static void 118 elf_x86_x86_write_secthead_rel(unsigned char *bufp, 119 elf_secthead *shead, 120 elf_section_index symtab_idx, 121 elf_section_index sindex) 122 { 123 YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); 124 YASM_WRITE_32_L(bufp, SHT_REL); 125 YASM_WRITE_32_L(bufp, 0); 126 YASM_WRITE_32_L(bufp, 0); 127 128 YASM_WRITE_32_L(bufp, shead->rel_offset); 129 YASM_WRITE_32_L(bufp, RELOC32_SIZE * shead->nreloc);/* size */ 130 YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ 131 YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ 132 133 YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ 134 YASM_WRITE_32_L(bufp, RELOC32_SIZE); /* entity size */ 135 } 136 137 static void 138 elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, 139 elf_reloc_entry *reloc, 140 unsigned long offset) 141 { 142 if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0) 143 { 144 yasm_intnum *off_intn = yasm_intnum_create_uint(offset); 145 yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn); 146 yasm_intnum_destroy(off_intn); 147 } 148 return; /* .rel: Leave addend in intn */ 149 } 150 151 static unsigned int 152 elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc) 153 { 154 if (reloc->wrt) { 155 const elf_machine_ssym *ssym = (elf_machine_ssym *) 156 yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); 157 if (!ssym || reloc->valsize != ssym->size) 158 yasm_internal_error(N_("Unsupported WRT")); 159 160 /* Force TLS type; this is required by the linker. */ 161 if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { 162 elf_symtab_entry *esym; 163 164 esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); 165 if (esym) 166 esym->type = STT_TLS; 167 } 168 return (unsigned char) ssym->reloc; 169 } else if (reloc->is_GOT_sym && reloc->valsize == 32) { 170 return (unsigned char) R_386_GOTPC; 171 } else if (reloc->rtype_rel) { 172 switch (reloc->valsize) { 173 case 8: return (unsigned char) R_386_PC8; 174 case 16: return (unsigned char) R_386_PC16; 175 case 32: return (unsigned char) R_386_PC32; 176 default: yasm_internal_error(N_("Unsupported relocation size")); 177 } 178 } else { 179 switch (reloc->valsize) { 180 case 8: return (unsigned char) R_386_8; 181 case 16: return (unsigned char) R_386_16; 182 case 32: return (unsigned char) R_386_32; 183 default: yasm_internal_error(N_("Unsupported relocation size")); 184 } 185 } 186 return 0; 187 } 188 189 static void 190 elf_x86_x86_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, 191 unsigned int r_type, unsigned int r_sym) 192 { 193 YASM_WRITE_32I_L(bufp, reloc->reloc.addr); 194 YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); 195 } 196 197 static void 198 elf_x86_x86_write_proghead(unsigned char **bufpp, 199 elf_offset secthead_addr, 200 unsigned long secthead_count, 201 elf_section_index shstrtab_index) 202 { 203 unsigned char *bufp = *bufpp; 204 unsigned char *buf = bufp-4; 205 YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ 206 YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ 207 YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ 208 while (bufp-buf < EI_NIDENT) /* e_ident padding */ 209 YASM_WRITE_8(bufp, 0); 210 211 YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ 212 YASM_WRITE_16_L(bufp, EM_386); /* e_machine - or others */ 213 YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ 214 YASM_WRITE_32_L(bufp, 0); /* e_entry exection startaddr */ 215 YASM_WRITE_32_L(bufp, 0); /* e_phoff program header off */ 216 YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff section header off */ 217 YASM_WRITE_32_L(bufp, 0); /* e_flags also by arch */ 218 YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ 219 YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ 220 YASM_WRITE_16_L(bufp, 0); /* e_phnum */ 221 YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ 222 YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ 223 YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ 224 *bufpp = bufp; 225 } 226 227 const elf_machine_handler 228 elf_machine_handler_x86_x86 = { 229 "x86", "x86", ".rel", 230 SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE, 231 elf_x86_x86_accepts_reloc, 232 elf_x86_x86_write_symtab_entry, 233 elf_x86_x86_write_secthead, 234 elf_x86_x86_write_secthead_rel, 235 elf_x86_x86_handle_reloc_addend, 236 elf_x86_x86_map_reloc_info_to_type, 237 elf_x86_x86_write_reloc, 238 elf_x86_x86_write_proghead, 239 elf_x86_x86_ssyms, 240 sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]), 241 32 242 }; 243