MipsRelocationFactory.cpp revision affc150dc44fab1911775a49636d0ce85333b634
1//===- MipsRelocationFactory.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#include <llvm/ADT/Twine.h> 11#include <llvm/Support/ELF.h> 12#include <mcld/LD/Layout.h> 13#include <mcld/Target/OutputRelocSection.h> 14#include <mcld/Support/MsgHandling.h> 15 16#include "MipsRelocationFactory.h" 17#include "MipsRelocationFunctions.h" 18 19using namespace mcld; 20 21DECL_MIPS_APPLY_RELOC_FUNCS 22 23//========================== 24// MipsRelocationFactory 25MipsRelocationFactory::MipsRelocationFactory(size_t pNum, 26 MipsGNULDBackend& pParent) 27 : RelocationFactory(pNum), 28 m_Target(pParent), 29 m_AHL(0) 30{ 31} 32 33void MipsRelocationFactory::applyRelocation(Relocation& pRelocation, 34 const MCLDInfo& pLDInfo) 35 36{ 37 /// the prototype of applying function 38 typedef Result (*ApplyFunctionType)(Relocation&, 39 const MCLDInfo& pLDInfo, 40 MipsRelocationFactory&); 41 42 // the table entry of applying functions 43 struct ApplyFunctionTriple { 44 ApplyFunctionType func; 45 unsigned int type; 46 const char* name; 47 }; 48 49 // declare the table of applying functions 50 static ApplyFunctionTriple apply_functions[] = { 51 DECL_MIPS_APPLY_RELOC_FUNC_PTRS 52 }; 53 54 Relocation::Type type = pRelocation.type(); 55 56 if (type >= sizeof(apply_functions) / sizeof(apply_functions[0])) { 57 fatal(diag::unknown_relocation) << (int)type 58 << pRelocation.symInfo()->name(); 59 } 60 61 // apply the relocation 62 Result result = apply_functions[type].func(pRelocation, pLDInfo, *this); 63 64 // check result 65 if (OK == result) { 66 return; 67 } 68 if (Overflow == result) { 69 error(diag::result_overflow) << apply_functions[type].name 70 << pRelocation.symInfo()->name(); 71 return; 72 } 73 74 if (BadReloc == result) { 75 error(diag::result_badreloc) << apply_functions[type].name 76 << pRelocation.symInfo()->name(); 77 return; 78 } 79} 80 81//=========================================// 82// Relocation helper function // 83//=========================================// 84 85static const char * const GP_DISP_NAME = "_gp_disp"; 86 87// Find next R_MIPS_LO16 relocation paired to pReloc. 88static 89Relocation* helper_FindLo16Reloc(Relocation& pReloc) 90{ 91 Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode()); 92 while (NULL != reloc) 93 { 94 if (llvm::ELF::R_MIPS_LO16 == reloc->type() && 95 reloc->symInfo() == pReloc.symInfo()) 96 return reloc; 97 98 reloc = static_cast<Relocation*>(reloc->getNextNode()); 99 } 100 return NULL; 101} 102 103// Check the symbol is _gp_disp. 104static 105bool helper_isGpDisp(const Relocation& pReloc) 106{ 107 const ResolveInfo* rsym = pReloc.symInfo(); 108 return 0 == strcmp(GP_DISP_NAME, rsym->name()); 109} 110 111static 112RelocationFactory::Address helper_GetGP(MipsRelocationFactory& pParent) 113{ 114 return pParent.getTarget().getGOT().getSection().addr() + 0x7FF0; 115} 116 117static 118GOTEntry& helper_GetGOTEntry(Relocation& pReloc, 119 MipsRelocationFactory& pParent, 120 bool& pExist, int32_t value) 121{ 122 // rsym - The relocation target symbol 123 ResolveInfo* rsym = pReloc.symInfo(); 124 MipsGNULDBackend& ld_backend = pParent.getTarget(); 125 MipsGOT& got = ld_backend.getGOT(); 126 127 GOTEntry& got_entry = *got.getEntry(*rsym, pExist); 128 129 if (pExist) 130 return got_entry; 131 132 // If we first get this GOT entry, we should initialize it. 133 if (!(got.isLocal(rsym) && rsym->type() == ResolveInfo::Section)) { 134 if (rsym->reserved() & MipsGNULDBackend::ReserveGot) { 135 got_entry.setContent(pReloc.symValue()); 136 } 137 else { 138 fatal(diag::reserve_entry_number_mismatch) << "GOT"; 139 } 140 } 141 142 return got_entry; 143} 144 145static 146RelocationFactory::Address helper_GetGOTOffset(Relocation& pReloc, 147 MipsRelocationFactory& pParent) 148{ 149 bool exist; 150 GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, 0); 151 return pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0; 152} 153 154static 155int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc) 156{ 157 assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 || 158 pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) && 159 pLoReloc.type() == llvm::ELF::R_MIPS_LO16 && 160 "Incorrect type of relocation for AHL calculation"); 161 162 // Note the addend is section symbol offset here 163 assert (pHiReloc.addend() == pLoReloc.addend()); 164 165 int32_t AHI = pHiReloc.target(); 166 int32_t ALO = pLoReloc.target(); 167 int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) + pLoReloc.addend(); 168 return AHL; 169} 170 171static 172void helper_DynRel(Relocation& pReloc, 173 MipsRelocationFactory& pParent) 174{ 175 ResolveInfo* rsym = pReloc.symInfo(); 176 MipsGNULDBackend& ld_backend = pParent.getTarget(); 177 MipsGOT& got = ld_backend.getGOT(); 178 179 bool exist; 180 Relocation& rel_entry = 181 *ld_backend.getRelDyn().getEntry(*rsym, false, exist); 182 183 rel_entry.setType(llvm::ELF::R_MIPS_REL32); 184 rel_entry.targetRef() = pReloc.targetRef(); 185 186 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 187 RelocationFactory::DWord S = pReloc.symValue(); 188 189 if (got.isLocal(rsym)) { 190 rel_entry.setSymInfo(NULL); 191 pReloc.target() = A + S; 192 } 193 else { 194 rel_entry.setSymInfo(rsym); 195 // Don't add symbol value that will be resolved by the dynamic linker 196 pReloc.target() = A; 197 } 198} 199 200//=========================================// 201// Relocation functions implementation // 202//=========================================// 203 204// R_MIPS_NONE and those unsupported/deprecated relocation type 205static 206MipsRelocationFactory::Result none(Relocation& pReloc, 207 const MCLDInfo& pLDInfo, 208 MipsRelocationFactory& pParent) 209{ 210 return MipsRelocationFactory::OK; 211} 212 213// R_MIPS_32: S + A 214static 215MipsRelocationFactory::Result abs32(Relocation& pReloc, 216 const MCLDInfo& pLDInfo, 217 MipsRelocationFactory& pParent) 218{ 219 ResolveInfo* rsym = pReloc.symInfo(); 220 221 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 222 RelocationFactory::DWord S = pReloc.symValue(); 223 224 const LDSection* target_sect = pParent.getLayout().getOutputLDSection( 225 *(pReloc.targetRef().frag())); 226 assert(NULL != target_sect); 227 // If the flag of target section is not ALLOC, we will not scan this relocation 228 // but perform static relocation. (e.g., applying .debug section) 229 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) { 230 pReloc.target() = S + A; 231 return MipsRelocationFactory::OK; 232 } 233 234 if (rsym->reserved() & MipsGNULDBackend::ReserveRel) { 235 helper_DynRel(pReloc, pParent); 236 237 return MipsRelocationFactory::OK; 238 } 239 240 pReloc.target() = (S + A); 241 242 return MipsRelocationFactory::OK; 243} 244 245// R_MIPS_HI16: 246// local/external: ((AHL + S) - (short)(AHL + S)) >> 16 247// _gp_disp : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 248static 249MipsRelocationFactory::Result hi16(Relocation& pReloc, 250 const MCLDInfo& pLDInfo, 251 MipsRelocationFactory& pParent) 252{ 253 Relocation* lo_reloc = helper_FindLo16Reloc(pReloc); 254 assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16"); 255 256 int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc); 257 int32_t res = 0; 258 259 pParent.setAHL(AHL); 260 261 if (helper_isGpDisp(pReloc)) { 262 int32_t P = pReloc.place(pParent.getLayout()); 263 int32_t GP = helper_GetGP(pParent); 264 res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16; 265 } 266 else { 267 int32_t S = pReloc.symValue(); 268 res = ((AHL + S) - (int16_t)(AHL + S)) >> 16; 269 } 270 271 pReloc.target() &= 0xFFFF0000; 272 pReloc.target() |= (res & 0xFFFF); 273 274 return MipsRelocationFactory::OK; 275} 276 277// R_MIPS_LO16: 278// local/external: AHL + S 279// _gp_disp : AHL + GP - P + 4 280static 281MipsRelocationFactory::Result lo16(Relocation& pReloc, 282 const MCLDInfo& pLDInfo, 283 MipsRelocationFactory& pParent) 284{ 285 int32_t res = 0; 286 287 if (helper_isGpDisp(pReloc)) { 288 int32_t P = pReloc.place(pParent.getLayout()); 289 int32_t GP = helper_GetGP(pParent); 290 int32_t AHL = pParent.getAHL(); 291 res = AHL + GP - P + 4; 292 } 293 else { 294 int32_t S = pReloc.symValue(); 295 // The previous AHL may be for other hi/lo pairs. 296 // We need to calcuate the lo part now. It is easy. 297 // Remember to add the section offset to ALO. 298 int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend(); 299 res = ALO + S; 300 } 301 302 pReloc.target() &= 0xFFFF0000; 303 pReloc.target() |= (res & 0xFFFF); 304 305 return MipsRelocationFactory::OK; 306} 307 308// R_MIPS_GOT16: 309// local : G (calculate AHL and put high 16 bit to GOT) 310// external: G 311static 312MipsRelocationFactory::Result got16(Relocation& pReloc, 313 const MCLDInfo& pLDInfo, 314 MipsRelocationFactory& pParent) 315{ 316 ResolveInfo* rsym = pReloc.symInfo(); 317 RelocationFactory::Address G = 0; 318 319 if (rsym->isLocal()) { 320 Relocation* lo_reloc = helper_FindLo16Reloc(pReloc); 321 assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16"); 322 323 int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc); 324 int32_t S = pReloc.symValue(); 325 326 pParent.setAHL(AHL); 327 328 int32_t res = (AHL + S + 0x8000) & 0xFFFF0000; 329 bool exist; 330 GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, res); 331 332 got_entry.setContent(res); 333 G = pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0; 334 } 335 else { 336 G = helper_GetGOTOffset(pReloc, pParent); 337 } 338 339 pReloc.target() &= 0xFFFF0000; 340 pReloc.target() |= (G & 0xFFFF); 341 342 return MipsRelocationFactory::OK; 343} 344 345// R_MIPS_CALL16: G 346static 347MipsRelocationFactory::Result call16(Relocation& pReloc, 348 const MCLDInfo& pLDInfo, 349 MipsRelocationFactory& pParent) 350{ 351 RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent); 352 353 pReloc.target() &= 0xFFFF0000; 354 pReloc.target() |= (G & 0xFFFF); 355 356 return MipsRelocationFactory::OK; 357} 358 359// R_MIPS_GPREL32: A + S + GP0 - GP 360static 361MipsRelocationFactory::Result gprel32(Relocation& pReloc, 362 const MCLDInfo& pLDInfo, 363 MipsRelocationFactory& pParent) 364{ 365 // Remember to add the section offset to A. 366 int32_t A = pReloc.target() + pReloc.addend(); 367 int32_t S = pReloc.symValue(); 368 int32_t GP = helper_GetGP(pParent); 369 370 // llvm does not emits SHT_MIPS_REGINFO section. 371 // Assume that GP0 is zero. 372 pReloc.target() = (A + S - GP) & 0xFFFFFFFF; 373 374 return MipsRelocationFactory::OK; 375} 376