• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- FragmentLinker.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 //
10 // This file implements the FragmentLinker class
11 //
12 //===----------------------------------------------------------------------===//
13 #include <mcld/Fragment/FragmentLinker.h>
14 
15 #include <llvm/Support/Host.h>
16 #include <llvm/Support/raw_ostream.h>
17 #include <llvm/Support/Casting.h>
18 
19 #include <mcld/LinkerConfig.h>
20 #include <mcld/Module.h>
21 #include <mcld/LD/LDSection.h>
22 #include <mcld/MC/MCLDInput.h>
23 #include <mcld/LD/LDSection.h>
24 #include <mcld/LD/BranchIslandFactory.h>
25 #include <mcld/LD/Resolver.h>
26 #include <mcld/LD/LDContext.h>
27 #include <mcld/LD/RelocationFactory.h>
28 #include <mcld/LD/RelocData.h>
29 #include <mcld/LD/Relocator.h>
30 #include <mcld/Support/MemoryRegion.h>
31 #include <mcld/Support/MemoryArea.h>
32 #include <mcld/Support/FileHandle.h>
33 #include <mcld/Support/MsgHandling.h>
34 #include <mcld/Target/TargetLDBackend.h>
35 #include <mcld/Fragment/Relocation.h>
36 
37 using namespace mcld;
38 
39 //===----------------------------------------------------------------------===//
40 // FragmentLinker
41 //===----------------------------------------------------------------------===//
42 /// Constructor
FragmentLinker(const LinkerConfig & pConfig,Module & pModule,TargetLDBackend & pBackend)43 FragmentLinker::FragmentLinker(const LinkerConfig& pConfig,
44                                Module& pModule,
45                                TargetLDBackend& pBackend)
46 
47   : m_Config(pConfig),
48     m_Module(pModule),
49     m_Backend(pBackend) {
50 }
51 
52 /// Destructor
~FragmentLinker()53 FragmentLinker::~FragmentLinker()
54 {
55 }
56 
finalizeSymbols()57 bool FragmentLinker::finalizeSymbols()
58 {
59   Module::sym_iterator symbol, symEnd = m_Module.sym_end();
60   for (symbol = m_Module.sym_begin(); symbol != symEnd; ++symbol) {
61 
62     if ((*symbol)->resolveInfo()->isAbsolute() ||
63         (*symbol)->resolveInfo()->type() == ResolveInfo::File) {
64       // absolute symbols or symbols with function type should have
65       // zero value
66       (*symbol)->setValue(0x0);
67       continue;
68     }
69 
70     if ((*symbol)->resolveInfo()->type() == ResolveInfo::ThreadLocal) {
71       m_Backend.finalizeTLSSymbol(**symbol);
72       continue;
73     }
74 
75     if ((*symbol)->hasFragRef()) {
76       // set the virtual address of the symbol. If the output file is
77       // relocatable object file, the section's virtual address becomes zero.
78       // And the symbol's value become section relative offset.
79       uint64_t value = (*symbol)->fragRef()->getOutputOffset();
80       assert(NULL != (*symbol)->fragRef()->frag());
81       uint64_t addr = (*symbol)->fragRef()->frag()->getParent()->getSection().addr();
82       (*symbol)->setValue(value + addr);
83       continue;
84     }
85   }
86 
87   return true;
88 }
89 
90 //===----------------------------------------------------------------------===//
91 // Relocation Operations
92 //===----------------------------------------------------------------------===//
applyRelocations()93 bool FragmentLinker::applyRelocations()
94 {
95   // when producing relocatables, no need to apply relocation
96   if (LinkerConfig::Object == m_Config.codeGenType())
97     return true;
98 
99   // apply all relocations of all inputs
100   Module::obj_iterator input, inEnd = m_Module.obj_end();
101   for (input = m_Module.obj_begin(); input != inEnd; ++input) {
102     m_Backend.getRelocator()->initializeApply(**input);
103     LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
104     for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
105       // bypass the reloc section if
106       // 1. its section kind is changed to Ignore. (The target section is a
107       // discarded group section.)
108       // 2. it has no reloc data. (All symbols in the input relocs are in the
109       // discarded group sections)
110       if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
111         continue;
112       RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
113       for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
114         Relocation* relocation = llvm::cast<Relocation>(reloc);
115         relocation->apply(*m_Backend.getRelocator());
116       } // for all relocations
117     } // for all relocation section
118     m_Backend.getRelocator()->finalizeApply(**input);
119   } // for all inputs
120 
121   // apply relocations created by relaxation
122   BranchIslandFactory* br_factory = m_Backend.getBRIslandFactory();
123   BranchIslandFactory::iterator facIter, facEnd = br_factory->end();
124   for (facIter = br_factory->begin(); facIter != facEnd; ++facIter) {
125     BranchIsland& island = *facIter;
126     BranchIsland::reloc_iterator iter, iterEnd = island.reloc_end();
127     for (iter = island.reloc_begin(); iter != iterEnd; ++iter)
128       (*iter)->apply(*m_Backend.getRelocator());
129   }
130   return true;
131 }
132 
133 
syncRelocationResult(MemoryArea & pOutput)134 void FragmentLinker::syncRelocationResult(MemoryArea& pOutput)
135 {
136   if (LinkerConfig::Object != m_Config.codeGenType())
137     normalSyncRelocationResult(pOutput);
138   else
139     partialSyncRelocationResult(pOutput);
140   return;
141 }
142 
normalSyncRelocationResult(MemoryArea & pOutput)143 void FragmentLinker::normalSyncRelocationResult(MemoryArea& pOutput)
144 {
145   MemoryRegion* region = pOutput.request(0, pOutput.handler()->size());
146 
147   uint8_t* data = region->getBuffer();
148 
149   // sync all relocations of all inputs
150   Module::obj_iterator input, inEnd = m_Module.obj_end();
151   for (input = m_Module.obj_begin(); input != inEnd; ++input) {
152     LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
153     for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
154       // bypass the reloc section if
155       // 1. its section kind is changed to Ignore. (The target section is a
156       // discarded group section.)
157       // 2. it has no reloc data. (All symbols in the input relocs are in the
158       // discarded group sections)
159       if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
160         continue;
161       RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
162       for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
163         Relocation* relocation = llvm::cast<Relocation>(reloc);
164 
165         // bypass the relocation with NONE type. This is to avoid overwrite the
166         // target result by NONE type relocation if there is a place which has
167         // two relocations to apply to, and one of it is NONE type. The result
168         // we want is the value of the other relocation result. For example,
169         // in .exidx, there are usually an R_ARM_NONE and R_ARM_PREL31 apply to
170         // the same place
171         if (0x0 == relocation->type())
172           continue;
173         writeRelocationResult(*relocation, data);
174       } // for all relocations
175     } // for all relocation section
176   } // for all inputs
177 
178   // sync relocations created by relaxation
179   BranchIslandFactory* br_factory = m_Backend.getBRIslandFactory();
180   BranchIslandFactory::iterator facIter, facEnd = br_factory->end();
181   for (facIter = br_factory->begin(); facIter != facEnd; ++facIter) {
182     BranchIsland& island = *facIter;
183     BranchIsland::reloc_iterator iter, iterEnd = island.reloc_end();
184     for (iter = island.reloc_begin(); iter != iterEnd; ++iter) {
185       Relocation* reloc = *iter;
186       writeRelocationResult(*reloc, data);
187     }
188   }
189 
190   pOutput.clear();
191 }
192 
partialSyncRelocationResult(MemoryArea & pOutput)193 void FragmentLinker::partialSyncRelocationResult(MemoryArea& pOutput)
194 {
195   MemoryRegion* region = pOutput.request(0, pOutput.handler()->size());
196 
197   uint8_t* data = region->getBuffer();
198 
199   // traverse outputs' LDSection to get RelocData
200   Module::iterator sectIter, sectEnd = m_Module.end();
201   for (sectIter = m_Module.begin(); sectIter != sectEnd; ++sectIter) {
202     if (LDFileFormat::Relocation != (*sectIter)->kind())
203       continue;
204 
205     RelocData* reloc_data = (*sectIter)->getRelocData();
206     RelocData::iterator relocIter, relocEnd = reloc_data->end();
207     for (relocIter = reloc_data->begin(); relocIter != relocEnd; ++relocIter) {
208       Relocation* reloc = llvm::cast<Relocation>(relocIter);
209 
210       // bypass the relocation with NONE type. This is to avoid overwrite the
211       // target result by NONE type relocation if there is a place which has
212       // two relocations to apply to, and one of it is NONE type. The result
213       // we want is the value of the other relocation result. For example,
214       // in .exidx, there are usually an R_ARM_NONE and R_ARM_PREL31 apply to
215       // the same place
216       if (0x0 == reloc->type())
217         continue;
218       writeRelocationResult(*reloc, data);
219     }
220   }
221 
222   pOutput.clear();
223 }
224 
writeRelocationResult(Relocation & pReloc,uint8_t * pOutput)225 void FragmentLinker::writeRelocationResult(Relocation& pReloc, uint8_t* pOutput)
226 {
227   // get output file offset
228   size_t out_offset =
229                  pReloc.targetRef().frag()->getParent()->getSection().offset() +
230                  pReloc.targetRef().getOutputOffset();
231 
232   uint8_t* target_addr = pOutput + out_offset;
233   // byte swapping if target and host has different endian, and then write back
234   if(llvm::sys::IsLittleEndianHost != m_Config.targets().isLittleEndian()) {
235      uint64_t tmp_data = 0;
236 
237      switch(pReloc.size(*m_Backend.getRelocator())) {
238        case 8u:
239          std::memcpy(target_addr, &pReloc.target(), 1);
240          break;
241 
242        case 16u:
243          tmp_data = mcld::bswap16(pReloc.target());
244          std::memcpy(target_addr, &tmp_data, 2);
245          break;
246 
247        case 32u:
248          tmp_data = mcld::bswap32(pReloc.target());
249          std::memcpy(target_addr, &tmp_data, 4);
250          break;
251 
252        case 64u:
253          tmp_data = mcld::bswap64(pReloc.target());
254          std::memcpy(target_addr, &tmp_data, 8);
255          break;
256 
257        default:
258          break;
259     }
260   }
261   else
262     std::memcpy(target_addr, &pReloc.target(),
263                                       pReloc.size(*m_Backend.getRelocator())/8);
264 }
265 
266