You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.2 KiB

//===- AArch64PLT.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AArch64GOT.h"
#include "AArch64PLT.h"
#include "AArch64RelocationHelpers.h"
#include "mcld/LD/LDSection.h"
#include "mcld/Support/MsgHandling.h"
#include <llvm/Support/Casting.h>
#include <new>
namespace mcld {
AArch64PLT0::AArch64PLT0(SectionData& pParent)
: PLT::Entry<sizeof(aarch64_plt0)>(pParent) {
}
AArch64PLT1::AArch64PLT1(SectionData& pParent)
: PLT::Entry<sizeof(aarch64_plt1)>(pParent) {
}
//===----------------------------------------------------------------------===//
// AArch64PLT
AArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT& pGOTPLT)
: PLT(pSection), m_GOT(pGOTPLT) {
new AArch64PLT0(*m_pSectionData);
}
AArch64PLT::~AArch64PLT() {
}
bool AArch64PLT::hasPLT1() const {
return (m_pSectionData->size() > 1);
}
void AArch64PLT::finalizeSectionSize() {
uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) +
sizeof(aarch64_plt0);
m_Section.setSize(size);
uint32_t offset = 0;
SectionData::iterator frag, fragEnd = m_pSectionData->end();
for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
frag->setOffset(offset);
offset += frag->size();
}
}
AArch64PLT1* AArch64PLT::create() {
AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData);
if (!plt1_entry)
fatal(diag::fail_allocate_memory_plt);
return plt1_entry;
}
void AArch64PLT::applyPLT0() {
// malloc plt0
iterator first = m_pSectionData->getFragmentList().begin();
assert(first != m_pSectionData->getFragmentList().end() &&
"FragmentList is empty, applyPLT0 failed!");
AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first));
uint32_t* data = NULL;
data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize));
if (data == NULL)
fatal(diag::fail_allocate_memory_plt);
memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize);
// apply plt0
uint64_t plt_base = m_Section.addr();
assert(plt_base && ".plt base address is NULL!");
uint64_t got_base = m_GOT.addr();
assert(got_base && ".got base address is NULL!");
// apply 2nd instruction
// get the address of got entry 2
uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2;
// compute the immediate
AArch64Relocator::DWord imm =
helper_get_page_address(got_ent2_base) -
helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8));
data[1] = helper_reencode_adr_imm(data[1], imm >> 12);
// apply 3rd instruction
data[2] = helper_reencode_add_imm(data[2],
helper_get_page_offset(got_ent2_base) >> 3);
// apply 4th instruction
data[3] =
helper_reencode_add_imm(data[3], helper_get_page_offset(got_ent2_base));
plt0->setValue(reinterpret_cast<unsigned char*>(data));
}
void AArch64PLT::applyPLT1() {
uint64_t plt_base = m_Section.addr();
assert(plt_base && ".plt base address is NULL!");
uint64_t got_base = m_GOT.addr();
assert(got_base && ".got base address is NULL!");
AArch64PLT::iterator it = m_pSectionData->begin();
AArch64PLT::iterator ie = m_pSectionData->end();
assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize;
// first gotplt1 address
uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
// first plt1 address
uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize;
++it; // skip PLT0
uint32_t PLT1EntrySize = AArch64PLT1::EntrySize;
AArch64PLT1* plt1 = NULL;
uint32_t* Out = NULL;
while (it != ie) {
plt1 = &(llvm::cast<AArch64PLT1>(*it));
Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize));
memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize);
// apply 1st instruction
AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) -
helper_get_page_address(PLTEntryAddress);
Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12);
// apply 2nd instruction
Out[1] = helper_reencode_add_imm(
Out[1], helper_get_page_offset(GOTEntryAddress) >> 3);
// apply 3rd instruction
Out[2] = helper_reencode_add_imm(Out[2],
helper_get_page_offset(GOTEntryAddress));
plt1->setValue(reinterpret_cast<unsigned char*>(Out));
++it;
GOTEntryAddress += GOTEntrySize;
PLTEntryAddress += PLT1EntrySize;
}
m_GOT.applyGOTPLT(plt_base);
}
uint64_t AArch64PLT::emit(MemoryRegion& pRegion) {
uint64_t result = 0x0;
iterator it = begin();
unsigned char* buffer = pRegion.begin();
memcpy(buffer,
llvm::cast<AArch64PLT0>((*it)).getValue(),
AArch64PLT0::EntrySize);
result += AArch64PLT0::EntrySize;
++it;
AArch64PLT1* plt1 = NULL;
AArch64PLT::iterator ie = end();
while (it != ie) {
plt1 = &(llvm::cast<AArch64PLT1>(*it));
memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize);
result += AArch64PLT1::EntrySize;
++it;
}
return result;
}
} // namespace mcld