/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "chre/platform/shared/nanoapp_loader.h" namespace chre { bool NanoappLoader::relocateTable(DynamicHeader *dyn, int tag) { bool success = false; if (dyn == nullptr) { return false; } switch (tag) { case DT_RELA: { if (getDynEntry(dyn, tag) == 0) { LOGE("RISC-V Elf binaries must have DT_RELA dynamic entry"); break; } // The value of the RELA entry in dynamic table is the sh_addr field // of ".rela.dyn" section header. We actually need to use the sh_offset // which is usually the same, but on occasions can be different. SectionHeader *dynamicRelaTablePtr = getSectionHeader(".rela.dyn"); CHRE_ASSERT(dynamicRelaTablePtr != nullptr); ElfRela *reloc = reinterpret_cast(mBinary + dynamicRelaTablePtr->sh_offset); size_t relocSize = dynamicRelaTablePtr->sh_size; size_t nRelocs = relocSize / sizeof(ElfRela); LOGV("Relocation %zu entries in DT_RELA table", nRelocs); for (size_t i = 0; i < nRelocs; ++i) { ElfRela *curr = &reloc[i]; int relocType = ELFW_R_TYPE(curr->r_info); ElfAddr *addr = reinterpret_cast(mMapping + curr->r_offset); switch (relocType) { case R_RISCV_RELATIVE: LOGV("Resolving RISCV_RELATIVE at offset %lx", static_cast(curr->r_offset)); // TODO(b/155512914): When we move to DRAM allocations, we need to // check if the above address is in a Read-Only section of memory, // and give it temporary write permission if that is the case. *addr = reinterpret_cast(mMapping + curr->r_addend); break; case R_RISCV_32: { LOGV("Resolving RISCV_32 at offset %lx", static_cast(curr->r_offset)); size_t posInSymbolTable = ELFW_R_SYM(curr->r_info); auto *dynamicSymbolTable = reinterpret_cast(mDynamicSymbolTablePtr); ElfSym *sym = &dynamicSymbolTable[posInSymbolTable]; *addr = reinterpret_cast(mMapping + sym->st_value); break; } default: LOGE("Unsupported relocation type %u", relocType); break; } } success = true; break; } case DT_REL: // Not required for RISC-V success = true; break; default: LOGE("Unsupported table tag %d", tag); } return success; } bool NanoappLoader::resolveGot() { ElfAddr *addr; ElfRela *reloc = reinterpret_cast( mMapping + getDynEntry(getDynamicHeader(), DT_JMPREL)); size_t relocSize = getDynEntry(getDynamicHeader(), DT_PLTRELSZ); size_t nRelocs = relocSize / sizeof(ElfRela); LOGV("Resolving GOT with %zu relocations", nRelocs); bool success = true; for (size_t i = 0; i < nRelocs; ++i) { ElfRela *curr = &reloc[i]; int relocType = ELFW_R_TYPE(curr->r_info); switch (relocType) { case R_RISCV_JUMP_SLOT: { LOGV("Resolving RISCV_JUMP_SLOT at offset %lx, %d", static_cast(curr->r_offset), curr->r_addend); addr = reinterpret_cast(mMapping + curr->r_offset); size_t posInSymbolTable = ELFW_R_SYM(curr->r_info); void *resolved = resolveData(posInSymbolTable); if (resolved == nullptr) { LOGE("Failed to resolve symbol(%zu) at offset 0x%x", i, curr->r_offset); success = false; } *addr = reinterpret_cast(resolved) + curr->r_addend; break; } default: LOGE("Unsupported relocation type: %u for symbol %s", relocType, getDataName(getDynamicSymbol(ELFW_R_SYM(curr->r_info)))); success = false; } } return success; } } // namespace chre