/* * Copyright 2012-2018, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Ithamar R. Adema */ #include #include #include #include "runtime_loader_private.h" #include static status_t relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel, size_t relLength, SymbolLookupCache* cache) { for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) { int type = ELF64_R_TYPE(rel[i].r_info); int symIndex = ELF64_R_SYM(rel[i].r_info); Elf64_Addr symAddr = 0; image_t* symbolImage = NULL; // Resolve the symbol, if any. if (symIndex != 0) { Elf64_Sym* sym = SYMBOL(image, symIndex); status_t status = resolve_symbol(rootImage, image, sym, cache, &symAddr, &symbolImage); if (status != B_OK) { TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n", SYMNAME(image, sym), status)); printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n", SYMNAME(image, sym), status); return status; } } // Address of the relocation. Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset; // Calculate the relocation value. Elf64_Addr relocValue; switch (type) { case R_RISCV_NONE: continue; case R_RISCV_64: case R_RISCV_JUMP_SLOT: relocValue = symAddr + rel[i].r_addend; break; case R_RISCV_RELATIVE: relocValue = image->regions[0].delta + rel[i].r_addend; break; case R_RISCV_TLS_DTPMOD64: relocValue = symbolImage == NULL ? image->dso_tls_id : symbolImage->dso_tls_id; break; case R_RISCV_TLS_DTPREL64: relocValue = symAddr; break; default: TRACE(("unhandled relocation type %d\n", type)); return B_BAD_DATA; } *(Elf64_Addr *)relocAddr = relocValue; } return B_OK; } status_t arch_relocate_image(image_t* rootImage, image_t* image, SymbolLookupCache* cache) { status_t status; // Perform RELA relocations. if (image->rela) { status = relocate_rela(rootImage, image, image->rela, image->rela_len, cache); if (status != B_OK) return status; } // PLT relocations (they are RELA on riscv64). if (image->pltrel) { status = relocate_rela(rootImage, image, (Elf64_Rela*)image->pltrel, image->pltrel_len, cache); if (status != B_OK) return status; } return B_OK; }