1 //===- ARMPLT.cpp ---------------------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "ARMGOT.h"
10 #include "ARMPLT.h"
11 
12 #include "mcld/LD/LDSection.h"
13 #include "mcld/Support/MsgHandling.h"
14 
15 #include <new>
16 
17 #include <llvm/Support/Casting.h>
18 
19 namespace mcld {
20 
ARMPLT0(SectionData & pParent)21 ARMPLT0::ARMPLT0(SectionData& pParent) : PLT::Entry<sizeof(arm_plt0)>(pParent) {
22 }
23 
ARMPLT1(SectionData & pParent)24 ARMPLT1::ARMPLT1(SectionData& pParent) : PLT::Entry<sizeof(arm_plt1)>(pParent) {
25 }
26 
27 //===----------------------------------------------------------------------===//
28 // ARMPLT
29 
ARMPLT(LDSection & pSection,ARMGOT & pGOTPLT)30 ARMPLT::ARMPLT(LDSection& pSection, ARMGOT& pGOTPLT)
31     : PLT(pSection), m_GOT(pGOTPLT) {
32   new ARMPLT0(*m_pSectionData);
33 }
34 
~ARMPLT()35 ARMPLT::~ARMPLT() {
36 }
37 
hasPLT1() const38 bool ARMPLT::hasPLT1() const {
39   return (m_pSectionData->size() > 1);
40 }
41 
finalizeSectionSize()42 void ARMPLT::finalizeSectionSize() {
43   uint64_t size =
44       (m_pSectionData->size() - 1) * sizeof(arm_plt1) + sizeof(arm_plt0);
45   m_Section.setSize(size);
46 
47   uint32_t offset = 0;
48   SectionData::iterator frag, fragEnd = m_pSectionData->end();
49   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
50     frag->setOffset(offset);
51     offset += frag->size();
52   }
53 }
54 
create()55 ARMPLT1* ARMPLT::create() {
56   ARMPLT1* plt1_entry = new (std::nothrow) ARMPLT1(*m_pSectionData);
57   if (!plt1_entry)
58     fatal(diag::fail_allocate_memory_plt);
59   return plt1_entry;
60 }
61 
applyPLT0()62 void ARMPLT::applyPLT0() {
63   uint64_t plt_base = m_Section.addr();
64   assert(plt_base && ".plt base address is NULL!");
65 
66   uint64_t got_base = m_GOT.addr();
67   assert(got_base && ".got base address is NULL!");
68 
69   uint32_t offset = 0;
70 
71   if (got_base > plt_base)
72     offset = got_base - (plt_base + 16);
73   else
74     offset = (plt_base + 16) - got_base;
75 
76   iterator first = m_pSectionData->getFragmentList().begin();
77 
78   assert(first != m_pSectionData->getFragmentList().end() &&
79          "FragmentList is empty, applyPLT0 failed!");
80 
81   ARMPLT0* plt0 = &(llvm::cast<ARMPLT0>(*first));
82 
83   uint32_t* data = 0;
84   data = static_cast<uint32_t*>(malloc(ARMPLT0::EntrySize));
85 
86   if (!data)
87     fatal(diag::fail_allocate_memory_plt);
88 
89   memcpy(data, arm_plt0, ARMPLT0::EntrySize);
90   data[4] = offset;
91 
92   plt0->setValue(reinterpret_cast<unsigned char*>(data));
93 }
94 
applyPLT1()95 void ARMPLT::applyPLT1() {
96   uint64_t plt_base = m_Section.addr();
97   assert(plt_base && ".plt base address is NULL!");
98 
99   uint64_t got_base = m_GOT.addr();
100   assert(got_base && ".got base address is NULL!");
101 
102   ARMPLT::iterator it = m_pSectionData->begin();
103   ARMPLT::iterator ie = m_pSectionData->end();
104   assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
105 
106   uint32_t GOTEntrySize = ARMGOTEntry::EntrySize;
107   uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
108 
109   uint64_t PLTEntryAddress = plt_base + ARMPLT0::EntrySize;  // Offset of PLT0
110 
111   ++it;  // skip PLT0
112   uint64_t PLT1EntrySize = ARMPLT1::EntrySize;
113   ARMPLT1* plt1 = NULL;
114 
115   uint32_t* Out = NULL;
116   while (it != ie) {
117     plt1 = &(llvm::cast<ARMPLT1>(*it));
118     Out = static_cast<uint32_t*>(malloc(ARMPLT1::EntrySize));
119 
120     if (!Out)
121       fatal(diag::fail_allocate_memory_plt);
122 
123     // Offset is the distance between the last PLT entry and the associated
124     // GOT entry.
125     int32_t Offset = (GOTEntryAddress - (PLTEntryAddress + 8));
126 
127     Out[0] = arm_plt1[0] | ((Offset >> 20) & 0xFF);
128     Out[1] = arm_plt1[1] | ((Offset >> 12) & 0xFF);
129     Out[2] = arm_plt1[2] | (Offset & 0xFFF);
130 
131     plt1->setValue(reinterpret_cast<unsigned char*>(Out));
132     ++it;
133 
134     GOTEntryAddress += GOTEntrySize;
135     PLTEntryAddress += PLT1EntrySize;
136   }
137 
138   m_GOT.applyGOTPLT(plt_base);
139 }
140 
emit(MemoryRegion & pRegion)141 uint64_t ARMPLT::emit(MemoryRegion& pRegion) {
142   uint64_t result = 0x0;
143   iterator it = begin();
144 
145   unsigned char* buffer = pRegion.begin();
146   memcpy(buffer, llvm::cast<ARMPLT0>((*it)).getValue(), ARMPLT0::EntrySize);
147   result += ARMPLT0::EntrySize;
148   ++it;
149 
150   ARMPLT1* plt1 = 0;
151   ARMPLT::iterator ie = end();
152   while (it != ie) {
153     plt1 = &(llvm::cast<ARMPLT1>(*it));
154     memcpy(buffer + result, plt1->getValue(), ARMPLT1::EntrySize);
155     result += ARMPLT1::EntrySize;
156     ++it;
157   }
158   return result;
159 }
160 
161 }  // namespace mcld
162