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