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