1 //===- X86RelocationFactory.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/ErrorHandling.h> 12 #include <llvm/Support/DataTypes.h> 13 #include <llvm/Support/ELF.h> 14 #include <mcld/MC/MCLDInfo.h> 15 #include <mcld/LD/Layout.h> 16 17 #include "X86RelocationFactory.h" 18 #include "X86RelocationFunctions.h" 19 20 using namespace mcld; 21 22 DECL_X86_APPLY_RELOC_FUNCS 23 24 //===--------------------------------------------------------------------===// 25 // X86RelocationFactory 26 X86RelocationFactory::X86RelocationFactory(size_t pNum, 27 X86GNULDBackend& pParent) 28 : RelocationFactory(pNum), 29 m_Target(pParent) { 30 } 31 32 X86RelocationFactory::~X86RelocationFactory() 33 { 34 } 35 36 void X86RelocationFactory::applyRelocation(Relocation& pRelocation, 37 const MCLDInfo& pLDInfo) 38 { 39 Relocation::Type type = pRelocation.type(); 40 41 /// the prototype of applying function 42 typedef Result (*ApplyFunctionType)(Relocation& pReloc, 43 const MCLDInfo& pLDInfo, 44 X86RelocationFactory& pParent); 45 46 // the table entry of applying functions 47 struct ApplyFunctionTriple { 48 ApplyFunctionType func; 49 unsigned int type; 50 const char* name; 51 }; 52 53 // declare the table of applying functions 54 static ApplyFunctionTriple apply_functions[] = { 55 DECL_X86_APPLY_RELOC_FUNC_PTRS 56 }; 57 58 if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) { 59 llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") + 60 llvm::Twine((int) type) + 61 llvm::Twine(" to symbol `") + 62 pRelocation.symInfo()->name() + 63 llvm::Twine("'.")); 64 return; 65 } 66 67 // apply the relocation 68 Result result = apply_functions[type].func(pRelocation, pLDInfo, *this); 69 70 // check result 71 if (Overflow == result) { 72 llvm::report_fatal_error(llvm::Twine("Applying relocation `") + 73 llvm::Twine(apply_functions[type].name) + 74 llvm::Twine("' causes overflow. on symbol: `") + 75 llvm::Twine(pRelocation.symInfo()->name()) + 76 llvm::Twine("'.")); 77 return; 78 } 79 80 if (BadReloc == result) { 81 llvm::report_fatal_error(llvm::Twine("Applying relocation `") + 82 llvm::Twine(apply_functions[type].name) + 83 llvm::Twine("' encounters unexpected opcode. " 84 "on symbol: `") + 85 llvm::Twine(pRelocation.symInfo()->name()) + 86 llvm::Twine("'.")); 87 return; 88 } 89 } 90 91 92 93 // non-member functions 94 95 //=========================================// 96 // Relocation helper function // 97 //=========================================// 98 99 // Check if symbol can use relocation R_386_RELATIVE 100 static bool 101 helper_use_relative_reloc(const ResolveInfo& pSym, 102 const MCLDInfo& pLDInfo, 103 const X86RelocationFactory& pFactory) 104 105 { 106 // if symbol is dynamic or undefine or preemptible 107 if(pSym.isDyn() || 108 pSym.isUndef() || 109 pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output())) 110 return false; 111 return true; 112 } 113 114 static 115 GOTEntry& helper_get_GOT_and_init(Relocation& pReloc, 116 const MCLDInfo& pLDInfo, 117 X86RelocationFactory& pParent) 118 { 119 // rsym - The relocation target symbol 120 ResolveInfo* rsym = pReloc.symInfo(); 121 X86GNULDBackend& ld_backend = pParent.getTarget(); 122 123 bool exist; 124 GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist); 125 if (!exist) { 126 // If we first get this GOT entry, we should initialize it. 127 if (rsym->reserved() & X86GNULDBackend::ReserveGOT) { 128 // No corresponding dynamic relocation, initialize to the symbol value. 129 got_entry.setContent(pReloc.symValue()); 130 } 131 else if (rsym->reserved() & X86GNULDBackend::GOTRel) { 132 // Initialize corresponding dynamic relocation. 133 Relocation& rel_entry = 134 *ld_backend.getRelDyn().getEntry(*rsym, true, exist); 135 assert(!exist && "GOT entry not exist, but DynRel entry exist!"); 136 if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) { 137 // Initialize got entry to target symbol address 138 got_entry.setContent(pReloc.symValue()); 139 rel_entry.setType(llvm::ELF::R_386_RELATIVE); 140 rel_entry.setSymInfo(0); 141 } 142 else { 143 got_entry.setContent(0); 144 rel_entry.setType(llvm::ELF::R_386_GLOB_DAT); 145 rel_entry.setSymInfo(rsym); 146 } 147 rel_entry.targetRef().assign(got_entry); 148 } 149 else { 150 llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!"); 151 } 152 } 153 return got_entry; 154 } 155 156 157 static 158 X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent) 159 { 160 return pParent.getTarget().getGOT().getSection().addr(); 161 } 162 163 164 static 165 X86RelocationFactory::Address helper_GOT(Relocation& pReloc, 166 const MCLDInfo& pLDInfo, 167 X86RelocationFactory& pParent) 168 { 169 GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo, pParent); 170 return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry); 171 } 172 173 174 static 175 PLTEntry& helper_get_PLT_and_init(Relocation& pReloc, 176 X86RelocationFactory& pParent) 177 { 178 // rsym - The relocation target symbol 179 ResolveInfo* rsym = pReloc.symInfo(); 180 X86GNULDBackend& ld_backend = pParent.getTarget(); 181 182 bool exist; 183 PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist); 184 if (!exist) { 185 // If we first get this PLT entry, we should initialize it. 186 if (rsym->reserved() & X86GNULDBackend::ReservePLT) { 187 GOTEntry& gotplt_entry = 188 *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist); 189 // Initialize corresponding dynamic relocation. 190 Relocation& rel_entry = 191 *ld_backend.getRelPLT().getEntry(*rsym, true, exist); 192 assert(!exist && "PLT entry not exist, but DynRel entry exist!"); 193 rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT); 194 rel_entry.targetRef().assign(gotplt_entry); 195 rel_entry.setSymInfo(rsym); 196 } 197 else { 198 llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!"); 199 } 200 } 201 return plt_entry; 202 } 203 204 205 206 static 207 X86RelocationFactory::Address helper_PLT_ORG(X86RelocationFactory& pParent) 208 { 209 return pParent.getTarget().getPLT().getSection().addr(); 210 } 211 212 213 static 214 X86RelocationFactory::Address helper_PLT(Relocation& pReloc, 215 X86RelocationFactory& pParent) 216 { 217 PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent); 218 return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry); 219 } 220 221 // Get an relocation entry in .rel.dyn and set its type to pType, 222 // its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo() 223 static 224 void helper_DynRel(Relocation& pReloc, 225 X86RelocationFactory::Type pType, 226 X86RelocationFactory& pParent) 227 { 228 // rsym - The relocation target symbol 229 ResolveInfo* rsym = pReloc.symInfo(); 230 X86GNULDBackend& ld_backend = pParent.getTarget(); 231 bool exist; 232 233 Relocation& rel_entry = 234 *ld_backend.getRelDyn().getEntry(*rsym, false, exist); 235 rel_entry.setType(pType); 236 rel_entry.targetRef() = pReloc.targetRef(); 237 238 if(pType == llvm::ELF::R_386_RELATIVE) 239 rel_entry.setSymInfo(0); 240 else 241 rel_entry.setSymInfo(rsym); 242 } 243 244 245 //=========================================// 246 // Each relocation function implementation // 247 //=========================================// 248 249 // R_386_NONE 250 X86RelocationFactory::Result none(Relocation& pReloc, 251 const MCLDInfo& pLDInfo, 252 X86RelocationFactory& pParent) 253 { 254 return X86RelocationFactory::OK; 255 } 256 257 // R_386_32: S + A 258 X86RelocationFactory::Result abs32(Relocation& pReloc, 259 const MCLDInfo& pLDInfo, 260 X86RelocationFactory& pParent) 261 { 262 ResolveInfo* rsym = pReloc.symInfo(); 263 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 264 RelocationFactory::DWord S = pReloc.symValue(); 265 266 if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) { 267 helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); 268 pReloc.target() = S + A; 269 return X86RelocationFactory::OK; 270 } 271 else if(!rsym->isLocal()) { 272 if(rsym->reserved() & X86GNULDBackend::ReservePLT) { 273 S = helper_PLT(pReloc, pParent); 274 pReloc.target() = S + A; 275 } 276 if(rsym->reserved() & X86GNULDBackend::ReserveRel) { 277 if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) { 278 helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent); 279 } 280 else { 281 helper_DynRel(pReloc, pReloc.type(), pParent); 282 return X86RelocationFactory::OK; 283 } 284 } 285 } 286 287 // perform static relocation 288 pReloc.target() = S + A; 289 return X86RelocationFactory::OK; 290 } 291 292 // R_386_PC32: S + A - P 293 X86RelocationFactory::Result rel32(Relocation& pReloc, 294 const MCLDInfo& pLDInfo, 295 X86RelocationFactory& pParent) 296 { 297 // perform static relocation 298 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 299 pReloc.target() = pReloc.symValue() + A 300 - pReloc.place(pParent.getLayout()); 301 return X86RelocationFactory::OK; 302 } 303 304 // R_386_GOTOFF: S + A - GOT_ORG 305 X86RelocationFactory::Result gotoff32(Relocation& pReloc, 306 const MCLDInfo& pLDInfo, 307 X86RelocationFactory& pParent) 308 { 309 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 310 X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent); 311 X86RelocationFactory::Address S = pReloc.symValue(); 312 313 pReloc.target() = S + A - GOT_ORG; 314 return X86RelocationFactory::OK; 315 } 316 317 // R_386_GOTPC: GOT_ORG + A - P 318 X86RelocationFactory::Result gotpc32(Relocation& pReloc, 319 const MCLDInfo& pLDInfo, 320 X86RelocationFactory& pParent) 321 { 322 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 323 X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent); 324 // Apply relocation. 325 pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout()); 326 return X86RelocationFactory::OK; 327 } 328 329 // R_386_GOT32: GOT(S) + A - GOT_ORG 330 X86RelocationFactory::Result got32(Relocation& pReloc, 331 const MCLDInfo& pLDInfo, 332 X86RelocationFactory& pParent) 333 { 334 if(!(pReloc.symInfo()->reserved() 335 & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) { 336 return X86RelocationFactory::BadReloc; 337 } 338 X86RelocationFactory::Address GOT_S = helper_GOT(pReloc, pLDInfo, pParent); 339 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 340 X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent); 341 // Apply relocation. 342 pReloc.target() = GOT_S + A - GOT_ORG; 343 return X86RelocationFactory::OK; 344 } 345 346 // R_386_PLT32: PLT(S) + A - P 347 X86RelocationFactory::Result plt32(Relocation& pReloc, 348 const MCLDInfo& pLDInfo, 349 X86RelocationFactory& pParent) 350 { 351 // PLT_S depends on if there is a PLT entry. 352 X86RelocationFactory::Address PLT_S; 353 if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT)) 354 PLT_S = helper_PLT(pReloc, pParent); 355 else 356 PLT_S = pReloc.symValue(); 357 RelocationFactory::DWord A = pReloc.target() + pReloc.addend(); 358 X86RelocationFactory::Address P = pReloc.place(pParent.getLayout()); 359 pReloc.target() = PLT_S + A - P; 360 return X86RelocationFactory::OK; 361 } 362