Process one elf relocation with addend. */
| 216 | |
| 217 | /* Process one elf relocation with addend. */ |
| 218 | static int |
| 219 | elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, |
| 220 | int type, int local, elf_lookup_fn lookup) |
| 221 | { |
| 222 | Elf64_Addr *where, val; |
| 223 | Elf32_Addr *where32, val32; |
| 224 | Elf_Addr addr; |
| 225 | Elf_Addr addend; |
| 226 | Elf_Size rtype, symidx; |
| 227 | const Elf_Rel *rel; |
| 228 | const Elf_Rela *rela; |
| 229 | int error; |
| 230 | |
| 231 | switch (type) { |
| 232 | case ELF_RELOC_REL: |
| 233 | rel = (const Elf_Rel *)data; |
| 234 | where = (Elf_Addr *) (relocbase + rel->r_offset); |
| 235 | rtype = ELF_R_TYPE(rel->r_info); |
| 236 | symidx = ELF_R_SYM(rel->r_info); |
| 237 | /* Addend is 32 bit on 32 bit relocs */ |
| 238 | switch (rtype) { |
| 239 | case R_X86_64_PC32: |
| 240 | case R_X86_64_32S: |
| 241 | addend = *(Elf32_Addr *)where; |
| 242 | break; |
| 243 | default: |
| 244 | addend = *where; |
| 245 | break; |
| 246 | } |
| 247 | break; |
| 248 | case ELF_RELOC_RELA: |
| 249 | rela = (const Elf_Rela *)data; |
| 250 | where = (Elf_Addr *) (relocbase + rela->r_offset); |
| 251 | addend = rela->r_addend; |
| 252 | rtype = ELF_R_TYPE(rela->r_info); |
| 253 | symidx = ELF_R_SYM(rela->r_info); |
| 254 | break; |
| 255 | default: |
| 256 | panic("unknown reloc type %d\n", type); |
| 257 | } |
| 258 | |
| 259 | switch (rtype) { |
| 260 | case R_X86_64_NONE: /* none */ |
| 261 | break; |
| 262 | |
| 263 | case R_X86_64_64: /* S + A */ |
| 264 | error = lookup(lf, symidx, 1, &addr); |
| 265 | val = addr + addend; |
| 266 | if (error != 0) |
| 267 | return -1; |
| 268 | if (*where != val) |
| 269 | *where = val; |
| 270 | break; |
| 271 | |
| 272 | case R_X86_64_PC32: /* S + A - P */ |
| 273 | error = lookup(lf, symidx, 1, &addr); |
| 274 | where32 = (Elf32_Addr *)where; |
| 275 | val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where); |
no test coverage detected