1551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===- AArch64RelocationHelpers.h -----------------------------------------===// 2551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// 3551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// The MCLinker Project 4551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// 5551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// This file is distributed under the University of Illinois Open Source 6551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// License. See LICENSE.TXT for details. 7551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// 8551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===// 937b74a387bb3993387029859c2d9d051c41c724eStephen Hines#ifndef TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H_ 1037b74a387bb3993387029859c2d9d051c41c724eStephen Hines#define TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H_ 11551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 12551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64Relocator.h" 13551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <llvm/Support/Host.h> 14551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 15551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesnamespace mcld { 16551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===// 17551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// Relocation helper functions 18551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===// 19551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// Return true if overflow 2037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline bool helper_check_signed_overflow(Relocator::DWord pValue, 2137b74a387bb3993387029859c2d9d051c41c724eStephen Hines unsigned bits) { 22551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (bits >= sizeof(int64_t) * 8) 23551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return false; 24551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines int64_t signed_val = static_cast<int64_t>(pValue); 25551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines int64_t max = (1 << (bits - 1)) - 1; 26551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines int64_t min = -(1 << (bits - 1)); 27551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (signed_val > max || signed_val < min) 28551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return true; 29551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return false; 30551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 31551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 3237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline Relocator::Address helper_get_page_address( 3337b74a387bb3993387029859c2d9d051c41c724eStephen Hines Relocator::Address pValue) { 3437b74a387bb3993387029859c2d9d051c41c724eStephen Hines return (pValue & ~(Relocator::Address)0xFFF); 35551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 36551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 3737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline Relocator::Address helper_get_page_offset( 3837b74a387bb3993387029859c2d9d051c41c724eStephen Hines Relocator::Address pValue) { 3937b74a387bb3993387029859c2d9d051c41c724eStephen Hines return (pValue & (Relocator::Address)0xFFF); 40551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 41551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 4237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t get_mask(uint32_t pValue) { 43551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return ((1u << (pValue)) - 1); 44551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 45551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 4637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t helper_reencode_adr_imm(uint32_t pInst, uint32_t pImm) { 4737b74a387bb3993387029859c2d9d051c41c724eStephen Hines return (pInst & ~((get_mask(2) << 29) | (get_mask(19) << 5))) | 4837b74a387bb3993387029859c2d9d051c41c724eStephen Hines ((pImm & get_mask(2)) << 29) | ((pImm & (get_mask(19) << 2)) << 3); 49551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 50551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 51551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// Reencode the imm field of add immediate. 5237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t helper_reencode_add_imm(uint32_t pInst, uint32_t pImm) { 53551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (pInst & ~(get_mask(12) << 10)) | ((pImm & get_mask(12)) << 10); 54551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 55551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 56551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// Encode the 26-bit offset of unconditional branch. 5737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t helper_reencode_branch_offset_26(uint32_t pInst, 5837b74a387bb3993387029859c2d9d051c41c724eStephen Hines uint32_t pOff) { 59551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (pInst & ~get_mask(26)) | (pOff & get_mask(26)); 60551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 61551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 62551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// Encode the 19-bit offset of conditional branch and compare & branch. 6337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t helper_reencode_cond_branch_ofs_19(uint32_t pInst, 6437b74a387bb3993387029859c2d9d051c41c724eStephen Hines uint32_t pOff) { 65551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (pInst & ~(get_mask(19) << 5)) | ((pOff & get_mask(19)) << 5); 66551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 67551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// Reencode the imm field of ld/st pos immediate. 6937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t helper_reencode_ldst_pos_imm(uint32_t pInst, 7037b74a387bb3993387029859c2d9d051c41c724eStephen Hines uint32_t pImm) { 71551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (pInst & ~(get_mask(12) << 10)) | ((pImm & get_mask(12)) << 10); 72551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 73551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 7437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline uint32_t helper_get_upper32(Relocator::DWord pData) { 75551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (llvm::sys::IsLittleEndianHost) 76551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return pData >> 32; 77551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return pData & 0xFFFFFFFF; 78551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 79551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 8037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline void helper_put_upper32(uint32_t pData, Relocator::DWord& pDes) { 81551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines *(reinterpret_cast<uint32_t*>(&pDes)) = pData; 82551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 83551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 8437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline Relocator::Address helper_get_PLT_address( 8537b74a387bb3993387029859c2d9d051c41c724eStephen Hines ResolveInfo& pSym, 8637b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64Relocator& pParent) { 87551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(pSym); 8837b74a387bb3993387029859c2d9d051c41c724eStephen Hines assert(plt_entry != NULL); 89551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return pParent.getTarget().getPLT().addr() + plt_entry->getOffset(); 90551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 91551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 9237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline AArch64PLT1& helper_PLT_init(Relocation& pReloc, 9337b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64Relocator& pParent) { 94551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // rsym - The relocation target symbol 95551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ResolveInfo* rsym = pReloc.symInfo(); 96551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64GNULDBackend& ld_backend = pParent.getTarget(); 9737b74a387bb3993387029859c2d9d051c41c724eStephen Hines assert(pParent.getSymPLTMap().lookUp(*rsym) == NULL); 98551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 99551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt_entry = ld_backend.getPLT().create(); 100551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines pParent.getSymPLTMap().record(*rsym, *plt_entry); 101551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 102551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // initialize plt and the corresponding gotplt and dyn rel entry. 10337b74a387bb3993387029859c2d9d051c41c724eStephen Hines assert(pParent.getSymGOTPLTMap().lookUp(*rsym) == NULL && 104551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines "PLT entry not exist, but DynRel entry exist!"); 105551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64GOTEntry* gotplt_entry = ld_backend.getGOTPLT().createGOTPLT(); 106551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry); 107551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 108551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // init the corresponding rel entry in .rela.plt 109551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Relocation& rel_entry = *ld_backend.getRelaPLT().create(); 110a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines rel_entry.setType(llvm::ELF::R_AARCH64_JUMP_SLOT); 111551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.targetRef().assign(*gotplt_entry); 112551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.setSymInfo(rsym); 113551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return *plt_entry; 114551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 115551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 116551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines/// helper_DynRel - Get an relocation entry in .rela.dyn 11737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline Relocation& helper_DynRela_init(ResolveInfo* pSym, 11837b74a387bb3993387029859c2d9d051c41c724eStephen Hines Fragment& pFrag, 11937b74a387bb3993387029859c2d9d051c41c724eStephen Hines uint64_t pOffset, 12037b74a387bb3993387029859c2d9d051c41c724eStephen Hines Relocator::Type pType, 12137b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64Relocator& pParent) { 122551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64GNULDBackend& ld_backend = pParent.getTarget(); 123551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Relocation& rel_entry = *ld_backend.getRelaDyn().create(); 124551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.setType(pType); 125551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.targetRef().assign(pFrag, pOffset); 126a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines if (pType == llvm::ELF::R_AARCH64_RELATIVE || pSym == NULL) 127551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.setSymInfo(NULL); 128551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines else 129551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.setSymInfo(pSym); 130551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 131551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return rel_entry; 132551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 133551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 134551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines/// helper_use_relative_reloc - Check if symbol can use relocation 135551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines/// R_AARCH64_RELATIVE 13637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline bool helper_use_relative_reloc(const ResolveInfo& pSym, 13737b74a387bb3993387029859c2d9d051c41c724eStephen Hines const AArch64Relocator& pParent) { 138551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // if symbol is dynamic or undefine or preemptible 13937b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (pSym.isDyn() || pSym.isUndef() || 140551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines pParent.getTarget().isSymbolPreemptible(pSym)) 141551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return false; 142551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return true; 143551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 144551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 14537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline Relocator::Address helper_get_GOT_address( 14637b74a387bb3993387029859c2d9d051c41c724eStephen Hines ResolveInfo& pSym, 14737b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64Relocator& pParent) { 148551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym); 14937b74a387bb3993387029859c2d9d051c41c724eStephen Hines assert(got_entry != NULL); 150551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return pParent.getTarget().getGOT().addr() + got_entry->getOffset(); 151551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 152551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 15337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline Relocator::Address helper_GOT_ORG(AArch64Relocator& pParent) { 154551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return pParent.getTarget().getGOT().addr(); 155551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 156551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 15737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline AArch64GOTEntry& helper_GOT_init(Relocation& pReloc, 15837b74a387bb3993387029859c2d9d051c41c724eStephen Hines bool pHasRel, 15937b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64Relocator& pParent) { 160551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // rsym - The relocation target symbol 161551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ResolveInfo* rsym = pReloc.symInfo(); 162551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64GNULDBackend& ld_backend = pParent.getTarget(); 16337b74a387bb3993387029859c2d9d051c41c724eStephen Hines assert(pParent.getSymGOTMap().lookUp(*rsym) == NULL); 164551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 165551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64GOTEntry* got_entry = ld_backend.getGOT().createGOT(); 166551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines pParent.getSymGOTMap().record(*rsym, *got_entry); 167551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 168551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // If we first get this GOT entry, we should initialize it. 169551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (!pHasRel) { 170551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // No corresponding dynamic relocation, initialize to the symbol value. 171551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines got_entry->setValue(AArch64Relocator::SymVal); 17237b74a387bb3993387029859c2d9d051c41c724eStephen Hines } else { 173551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // Initialize got_entry content and the corresponding dynamic relocation. 174551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (helper_use_relative_reloc(*rsym, pParent)) { 175551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines got_entry->setValue(AArch64Relocator::SymVal); 17637b74a387bb3993387029859c2d9d051c41c724eStephen Hines Relocation& rel_entry = helper_DynRela_init( 177a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines rsym, *got_entry, 0x0, llvm::ELF::R_AARCH64_RELATIVE, pParent); 178551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines rel_entry.setAddend(AArch64Relocator::SymVal); 179551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines pParent.getRelRelMap().record(pReloc, rel_entry); 18037b74a387bb3993387029859c2d9d051c41c724eStephen Hines } else { 181a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines helper_DynRela_init(rsym, *got_entry, 0x0, llvm::ELF::R_AARCH64_GLOB_DAT, 182a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines pParent); 183551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines got_entry->setValue(0); 184551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 185551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 186551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return *got_entry; 187551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 188551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 18937b74a387bb3993387029859c2d9d051c41c724eStephen Hines} // namespace mcld 19037b74a387bb3993387029859c2d9d051c41c724eStephen Hines 19137b74a387bb3993387029859c2d9d051c41c724eStephen Hines#endif // TARGET_AARCH64_AARCH64RELOCATIONHELPERS_H_ 192