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