From 5a14d496ab3bab1e8603d33bc58f27318743f55e Mon Sep 17 00:00:00 2001 From: Konstantin Zhuravlyov Date: Wed, 25 May 2016 15:41:31 -0400 Subject: [PATCH] Add support for dynamic relocations (code object v2.1) Change-Id: Ic19be97d3ea78b53f5aa814787515b587d0be21b --- .../libamdhsacode/amd_elf_image.cpp | 6 +- .../libamdhsacode/amd_hsa_code.cpp | 8 +- runtime/hsa-runtime/loader/executable.cpp | 202 ++++++++++++++---- runtime/hsa-runtime/loader/executable.hpp | 9 +- 4 files changed, 174 insertions(+), 51 deletions(-) diff --git a/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp b/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp index df87480523..3f735c82be 100644 --- a/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp +++ b/runtime/hsa-runtime/libamdhsacode/amd_elf_image.cpp @@ -1368,7 +1368,7 @@ namespace amd { section = new GElfRelocationSection(this); } else if (shdr.sh_type == SHT_STRTAB) { section = new GElfStringTable(this); - } else if (shdr.sh_type == SHT_SYMTAB) { + } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { section = new GElfSymbolTable(this); } else if (shdr.sh_type == SHT_NULL) { section = 0; @@ -1391,14 +1391,14 @@ namespace amd { for (size_t n = 1; n < sections.size(); ++n) { GElfSection* section = sections[n].get(); - if (section->type() == SHT_SYMTAB) { + if (section->type() == SHT_SYMTAB || section->type() == SHT_DYNSYM) { if (!section->pullData()) { return false; } } } for (size_t n = 1; n < sections.size(); ++n) { GElfSection* section = sections[n].get(); - if (section->type() != SHT_STRTAB && section->type() != SHT_SYMTAB) { + if (section->type() != SHT_STRTAB && section->type() != SHT_SYMTAB && section->type() != SHT_DYNSYM) { if (!section->pullData()) { return false; } } } diff --git a/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp b/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp index ed87533591..464ca7d1dd 100644 --- a/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp +++ b/runtime/hsa-runtime/libamdhsacode/amd_hsa_code.cpp @@ -1181,7 +1181,13 @@ namespace code { void AmdHsaCode::PrintRelocationData(std::ostream& out, RelocationSection* section) { - out << " Relocation Entries for " << section->targetSection()->Name() << " Section (total " << section->relocationCount() << "):" << std::endl; + if (section->targetSection()) { + out << " Relocation Entries for " << section->targetSection()->Name() << " Section (total " << section->relocationCount() << "):" << std::endl; + } else { + // Dynamic relocations do not have a target section, they work with + // virtual addresses. + out << " Dynamic Relocation Entries (total " << section->relocationCount() << "):" << std::endl; + } for (size_t i = 0; i < section->relocationCount(); ++i) { out << " Relocation (Index " << i << "):" << std::endl; out << " Type: " << section->relocation(i)->type() << std::endl; diff --git a/runtime/hsa-runtime/loader/executable.cpp b/runtime/hsa-runtime/loader/executable.cpp index 734e4de8f0..45c6abd619 100644 --- a/runtime/hsa-runtime/loader/executable.cpp +++ b/runtime/hsa-runtime/loader/executable.cpp @@ -906,10 +906,8 @@ hsa_status_t ExecutableImpl::LoadCodeObject( if (status != HSA_STATUS_SUCCESS) { return status; } } - for (size_t i = 0; i < code->RelocationSectionCount(); ++i) { - status = LoadRelocationSection(agent, code->GetRelocationSection(i)); - if (status != HSA_STATUS_SUCCESS) { return status; } - } + status = ApplyRelocations(agent, code.get()); + if (status != HSA_STATUS_SUCCESS) { return status; } code.reset(); @@ -1073,6 +1071,16 @@ hsa_status_t ExecutableImpl::LoadDeclarationSymbol(hsa_agent_t agent, code::Symb return HSA_STATUS_SUCCESS; } +Segment* ExecutableImpl::VirtualAddressSegment(uint64_t vaddr) +{ + for (auto &seg : loaded_code_objects.back()->LoadedSegments()) { + if (seg->IsAddressInSegment(vaddr)) { + return seg; + } + } + return 0; +} + uint64_t ExecutableImpl::SymbolAddress(hsa_agent_t agent, code::Symbol* sym) { code::Section* sec = sym->GetSection(); @@ -1103,19 +1111,46 @@ Segment* ExecutableImpl::SectionSegment(hsa_agent_t agent, code::Section* sec) return 0; } -hsa_status_t ExecutableImpl::LoadRelocationSection(hsa_agent_t agent, code::RelocationSection* sec) +hsa_status_t ExecutableImpl::ApplyRelocations(hsa_agent_t agent, amd::hsa::code::AmdHsaCode *c) { - hsa_status_t status; - for (size_t i = 0; i < sec->relocationCount(); ++i) { - status = LoadRelocation(agent, sec->relocation(i)); + hsa_status_t status = HSA_STATUS_SUCCESS; + for (size_t i = 0; i < c->RelocationSectionCount(); ++i) { + if (c->GetRelocationSection(i)->targetSection()) { + status = ApplyStaticRelocationSection(agent, c->GetRelocationSection(i)); + } else { + // Dynamic relocations are supported starting code object v2.1. + uint32_t majorVersion, minorVersion; + if (!c->GetNoteCodeObjectVersion(&majorVersion, &minorVersion)) { + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } + if (majorVersion < 2) { + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } + if (majorVersion == 2 && minorVersion < 1) { + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } + status = ApplyDynamicRelocationSection(agent, c->GetRelocationSection(i)); + } if (status != HSA_STATUS_SUCCESS) { return status; } } return HSA_STATUS_SUCCESS; } -hsa_status_t ExecutableImpl::LoadRelocation(hsa_agent_t agent, code::Relocation* rel) +hsa_status_t ExecutableImpl::ApplyStaticRelocationSection(hsa_agent_t agent, amd::hsa::code::RelocationSection* sec) { - hsa_status_t status; + // Skip link-time relocations (if any). + if (!(sec->targetSection()->flags() & SHF_ALLOC)) { return HSA_STATUS_SUCCESS; } + hsa_status_t status = HSA_STATUS_SUCCESS; + for (size_t i = 0; i < sec->relocationCount(); ++i) { + status = ApplyStaticRelocation(agent, sec->relocation(i)); + if (status != HSA_STATUS_SUCCESS) { return status; } + } + return HSA_STATUS_SUCCESS; +} + +hsa_status_t ExecutableImpl::ApplyStaticRelocation(hsa_agent_t agent, amd::hsa::code::Relocation *rel) +{ + hsa_status_t status = HSA_STATUS_SUCCESS; amd::elf::Symbol* sym = rel->symbol(); code::RelocationSection* rsec = rel->section(); code::Section* sec = rsec->targetSection(); @@ -1128,43 +1163,43 @@ hsa_status_t ExecutableImpl::LoadRelocation(hsa_agent_t agent, code::Relocation* { uint64_t addr; switch (sym->type()) { - case STT_OBJECT: - case STT_SECTION: - case STT_AMDGPU_HSA_KERNEL: - case STT_AMDGPU_HSA_INDIRECT_FUNCTION: - addr = SymbolAddress(agent, sym); - if (!addr) { return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; } - break; - case STT_COMMON: { - hsa_agent_t sagent = agent; - if (STA_AMDGPU_HSA_GLOBAL_PROGRAM == ELF64_ST_AMDGPU_ALLOCATION(sym->other())) { - sagent.handle = 0; + case STT_OBJECT: + case STT_SECTION: + case STT_AMDGPU_HSA_KERNEL: + case STT_AMDGPU_HSA_INDIRECT_FUNCTION: + addr = SymbolAddress(agent, sym); + if (!addr) { return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; } + break; + case STT_COMMON: { + hsa_agent_t sagent = agent; + if (STA_AMDGPU_HSA_GLOBAL_PROGRAM == ELF64_ST_AMDGPU_ALLOCATION(sym->other())) { + sagent.handle = 0; + } + SymbolImpl* esym = (SymbolImpl*) GetSymbolInternal("", sym->name().c_str(), sagent, 0); + if (!esym) { return HSA_STATUS_ERROR_VARIABLE_UNDEFINED; } + addr = esym->address; + break; } - SymbolImpl* esym = (SymbolImpl*) GetSymbolInternal("", sym->name().c_str(), sagent, 0); - if (!esym) { return HSA_STATUS_ERROR_VARIABLE_UNDEFINED; } - addr = esym->address; - break; - } - default: - return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + default: + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; } addr += rel->addend(); uint32_t addr32 = 0; switch (rel->type()) { - case R_AMDGPU_32_HIGH: - addr32 = uint32_t((addr >> 32) & 0xFFFFFFFF); - rseg->Copy(reladdr, &addr32, sizeof(addr32)); - break; - case R_AMDGPU_32_LOW: - addr32 = uint32_t(addr & 0xFFFFFFFF); - rseg->Copy(reladdr, &addr32, sizeof(addr32)); - break; - case R_AMDGPU_64: - rseg->Copy(reladdr, &addr, sizeof(addr)); - break; - default: - return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + case R_AMDGPU_32_HIGH: + addr32 = uint32_t((addr >> 32) & 0xFFFFFFFF); + rseg->Copy(reladdr, &addr32, sizeof(addr32)); + break; + case R_AMDGPU_32_LOW: + addr32 = uint32_t(addr & 0xFFFFFFFF); + rseg->Copy(reladdr, &addr32, sizeof(addr32)); + break; + case R_AMDGPU_64: + rseg->Copy(reladdr, &addr, sizeof(addr)); + break; + default: + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; } break; } @@ -1200,7 +1235,7 @@ hsa_status_t ExecutableImpl::LoadRelocation(hsa_agent_t agent, code::Relocation* break; } - case R_AMDGPU_INIT_IMAGE: + case R_AMDGPU_INIT_IMAGE: { if (STT_AMDGPU_HSA_METADATA != sym->type() || SHT_PROGBITS != sym->section()->type() || @@ -1263,9 +1298,86 @@ hsa_status_t ExecutableImpl::LoadRelocation(hsa_agent_t agent, code::Relocation* break; } - default: - // Ignore - break; + default: + // Ignore. + break; + } + return HSA_STATUS_SUCCESS; +} + +hsa_status_t ExecutableImpl::ApplyDynamicRelocationSection(hsa_agent_t agent, amd::hsa::code::RelocationSection* sec) +{ + hsa_status_t status = HSA_STATUS_SUCCESS; + for (size_t i = 0; i < sec->relocationCount(); ++i) { + status = ApplyDynamicRelocation(agent, sec->relocation(i)); + if (status != HSA_STATUS_SUCCESS) { return status; } + } + return HSA_STATUS_SUCCESS; +} + +hsa_status_t ExecutableImpl::ApplyDynamicRelocation(hsa_agent_t agent, amd::hsa::code::Relocation *rel) +{ + Segment* relSeg = VirtualAddressSegment(rel->offset()); + uint64_t symAddr = 0; + switch (rel->symbol()->type()) { + case STT_OBJECT: + case STT_AMDGPU_HSA_KERNEL: + { + Segment* symSeg = VirtualAddressSegment(rel->symbol()->value()); + symAddr = reinterpret_cast(symSeg->Address(rel->symbol()->value())); + break; + } + + // External symbols, they must be defined prior loading. + case STT_NOTYPE: + { + // TODO: Only agent allocation variables are supported in v2.1. How will + // we distinguish between program allocation and agent allocation + // variables? + auto agent_symbol = agent_symbols_.find(std::make_pair(rel->symbol()->name(), agent)); + if (agent_symbol == agent_symbols_.end()) { + // External symbols must be defined prior loading. + return HSA_STATUS_ERROR_VARIABLE_UNDEFINED; + } + symAddr = agent_symbol->second->address; + break; + } + + default: + // Only objects and kernels are supported in v2.1. + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + } + symAddr += rel->addend(); + + switch (rel->type()) { + case R_AMDGPU_32_HIGH: + { + uint32_t symAddr32 = uint32_t((symAddr >> 32) & 0xFFFFFFFF); + relSeg->Copy(rel->offset(), &symAddr32, sizeof(symAddr32)); + break; + } + + case R_AMDGPU_32_LOW: + { + uint32_t symAddr32 = uint32_t(symAddr & 0xFFFFFFFF); + relSeg->Copy(rel->offset(), &symAddr32, sizeof(symAddr32)); + break; + } + + case R_AMDGPU_64: + { + relSeg->Copy(rel->offset(), &symAddr, sizeof(symAddr)); + break; + } + + case R_AMDGPU_INIT_IMAGE: + case R_AMDGPU_INIT_SAMPLER: + // Images and samplers are not supported in v2.1. + return HSA_STATUS_ERROR_INVALID_CODE_OBJECT; + + default: + // Ignore. + break; } return HSA_STATUS_SUCCESS; } diff --git a/runtime/hsa-runtime/loader/executable.hpp b/runtime/hsa-runtime/loader/executable.hpp index 84df116204..6801be698b 100644 --- a/runtime/hsa-runtime/loader/executable.hpp +++ b/runtime/hsa-runtime/loader/executable.hpp @@ -425,9 +425,14 @@ private: hsa_status_t LoadSymbol(hsa_agent_t agent, amd::hsa::code::Symbol* sym); hsa_status_t LoadDefinitionSymbol(hsa_agent_t agent, amd::hsa::code::Symbol* sym); hsa_status_t LoadDeclarationSymbol(hsa_agent_t agent, amd::hsa::code::Symbol* sym); - hsa_status_t LoadRelocationSection(hsa_agent_t agent, amd::hsa::code::RelocationSection* sec); - hsa_status_t LoadRelocation(hsa_agent_t agent, amd::hsa::code::Relocation* rel); + hsa_status_t ApplyRelocations(hsa_agent_t agent, amd::hsa::code::AmdHsaCode *c); + hsa_status_t ApplyStaticRelocationSection(hsa_agent_t agent, amd::hsa::code::RelocationSection* sec); + hsa_status_t ApplyStaticRelocation(hsa_agent_t agent, amd::hsa::code::Relocation *rel); + hsa_status_t ApplyDynamicRelocationSection(hsa_agent_t agent, amd::hsa::code::RelocationSection* sec); + hsa_status_t ApplyDynamicRelocation(hsa_agent_t agent, amd::hsa::code::Relocation *rel); + + Segment* VirtualAddressSegment(uint64_t vaddr); uint64_t SymbolAddress(hsa_agent_t agent, amd::hsa::code::Symbol* sym); uint64_t SymbolAddress(hsa_agent_t agent, amd::elf::Symbol* sym); Segment* SymbolSegment(hsa_agent_t agent, amd::hsa::code::Symbol* sym);