• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- MipsPLT.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 <llvm/Support/Casting.h>
10 #include <llvm/Support/ELF.h>
11 #include <mcld/Support/MsgHandling.h>
12 #include "MipsGOTPLT.h"
13 #include "MipsPLT.h"
14 
15 namespace {
16 
17 const uint32_t PLT0[] = {
18   0x3c1c0000,         // lui $28, %hi(&GOTPLT[0])
19   0x8f990000,         // lw $25, %lo(&GOTPLT[0])($28)
20   0x279c0000,         // addiu $28, $28, %lo(&GOTPLT[0])
21   0x031cc023,         // subu $24, $24, $28
22   0x03e07821,         // move $15, $31
23   0x0018c082,         // srl $24, $24, 2
24   0x0320f809,         // jalr $25
25   0x2718fffe          // subu $24, $24, 2
26 };
27 
28 const uint32_t PLTA[] = {
29   0x3c0f0000,         // lui $15, %hi(.got.plt entry)
30   0x8df90000,         // l[wd] $25, %lo(.got.plt entry)($15)
31   0x03200008,         // jr $25
32   0x25f80000          // addiu $24, $15, %lo(.got.plt entry)
33 };
34 
35 }
36 
37 namespace mcld {
38 
39 //===----------------------------------------------------------------------===//
40 // MipsPLT0 Entry
41 //===----------------------------------------------------------------------===//
42 class MipsPLT0 : public PLT::Entry<sizeof(PLT0)>
43 {
44 public:
MipsPLT0(SectionData & pParent)45   MipsPLT0(SectionData& pParent)
46     : PLT::Entry<sizeof(PLT0)>(pParent)
47   {}
48 };
49 
50 //===----------------------------------------------------------------------===//
51 // MipsPLTA Entry
52 //===----------------------------------------------------------------------===//
53 class MipsPLTA : public PLT::Entry<sizeof(PLTA)>
54 {
55 public:
MipsPLTA(SectionData & pParent)56   MipsPLTA(SectionData& pParent)
57     : PLT::Entry<sizeof(PLTA)>(pParent)
58   {}
59 };
60 
61 //===----------------------------------------------------------------------===//
62 // MipsPLT
63 //===----------------------------------------------------------------------===//
MipsPLT(LDSection & pSection)64 MipsPLT::MipsPLT(LDSection& pSection)
65   : PLT(pSection)
66 {
67   new MipsPLT0(*m_pSectionData);
68   m_Last = m_pSectionData->begin();
69 }
70 
finalizeSectionSize()71 void MipsPLT::finalizeSectionSize()
72 {
73   uint64_t size = sizeof(PLT0) +
74                   (m_pSectionData->size() - 1) * sizeof(PLTA);
75   m_Section.setSize(size);
76 
77   uint32_t offset = 0;
78   SectionData::iterator frag, fragEnd = m_pSectionData->end();
79   for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
80     frag->setOffset(offset);
81     offset += frag->size();
82   }
83 }
84 
hasPLT1() const85 bool MipsPLT::hasPLT1() const
86 {
87   return m_pSectionData->size() > 1;
88 }
89 
emit(MemoryRegion & pRegion)90 uint64_t MipsPLT::emit(MemoryRegion& pRegion)
91 {
92   uint64_t result = 0x0;
93   iterator it = begin();
94 
95   unsigned char* buffer = pRegion.begin();
96   memcpy(buffer, llvm::cast<MipsPLT0>((*it)).getValue(), MipsPLT0::EntrySize);
97   result += MipsPLT0::EntrySize;
98   ++it;
99 
100   MipsPLTA* plta = 0;
101   for (iterator ie = end(); it != ie; ++it) {
102     plta = &(llvm::cast<MipsPLTA>(*it));
103     memcpy(buffer + result, plta->getValue(), MipsPLTA::EntrySize);
104     result += MipsPLTA::EntrySize;
105   }
106   return result;
107 }
108 
reserveEntry(size_t pNum)109 void MipsPLT::reserveEntry(size_t pNum)
110 {
111   for (size_t i = 0; i < pNum; ++i) {
112     Fragment* entry = new (std::nothrow) MipsPLTA(*m_pSectionData);
113 
114     if (NULL == entry)
115       fatal(diag::fail_allocate_memory_plt);
116   }
117 }
118 
consume()119 Fragment* MipsPLT::consume()
120 {
121   ++m_Last;
122   assert(m_Last != m_pSectionData->end() &&
123          "The number of PLT Entries and ResolveInfo doesn't match");
124   return &(*m_Last);
125 }
126 
applyAllPLT(MipsGOTPLT & pGOTPLT)127 void MipsPLT::applyAllPLT(MipsGOTPLT& pGOTPLT)
128 {
129   assert(m_Section.addr() && ".plt base address is NULL!");
130 
131   size_t count = 0;
132   for (iterator it = m_pSectionData->begin(); it != m_pSectionData->end(); ++it) {
133     PLTEntryBase* plt = &(llvm::cast<PLTEntryBase>(*it));
134 
135     if (it == m_pSectionData->begin()) {
136       uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
137 
138       if (!data)
139         fatal(diag::fail_allocate_memory_plt);
140 
141       memcpy(data, PLT0, plt->size());
142 
143       uint64_t gotAddr = pGOTPLT.addr();
144 
145       data[0] |= ((gotAddr + 0x8000) >> 16) & 0xffff;
146       data[1] |= gotAddr & 0xffff;
147       data[2] |= gotAddr & 0xffff;
148 
149       plt->setValue(reinterpret_cast<unsigned char*>(data));
150     } else {
151       uint32_t* data = static_cast<uint32_t*>(malloc(plt->size()));
152 
153       if (!data)
154         fatal(diag::fail_allocate_memory_plt);
155 
156       memcpy(data, PLTA, plt->size());
157 
158       uint64_t gotEntryAddr = pGOTPLT.getEntryAddr(count++);
159 
160       data[0] |= ((gotEntryAddr + 0x8000) >> 16) & 0xffff;
161       data[1] |= gotEntryAddr & 0xffff;
162       data[3] |= gotEntryAddr & 0xffff;
163 
164       plt->setValue(reinterpret_cast<unsigned char*>(data));
165     }
166   }
167 }
168 
169 } //end mcld namespace
170