137b74a387bb3993387029859c2d9d051c41c724eStephen Hines//===- ARMRelocator.cpp  --------------------------------------------------===//
25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//
35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//                     The MCLinker Project
45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//
55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// This file is distributed under the University of Illinois Open Source
65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// License. See LICENSE.TXT for details.
75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//
837b74a387bb3993387029859c2d9d051c41c724eStephen Hines//===----------------------------------------------------------------------===//
937b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "ARMRelocator.h"
1037b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "ARMRelocationFunctions.h"
1137b74a387bb3993387029859c2d9d051c41c724eStephen Hines
1237b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/IRBuilder.h"
1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LinkerConfig.h"
1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/ELFFileFormat.h"
1537b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/LDSymbol.h"
1637b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Object/ObjectBuilder.h"
1737b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/MsgHandling.h"
185460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <llvm/ADT/Twine.h>
205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <llvm/Support/DataTypes.h>
215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <llvm/Support/ELF.h>
22affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <llvm/Support/Host.h>
235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace mcld {
255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//=========================================//
2787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// Relocation helper function              //
2887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines//=========================================//
2937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord getThumbBit(const Relocation& pReloc) {
3087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // Set thumb bit if
3187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
3287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  Relocator::DWord thumbBit =
3337b74a387bb3993387029859c2d9d051c41c724eStephen Hines      ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
3437b74a387bb3993387029859c2d9d051c41c724eStephen Hines       (pReloc.symInfo()->type() == ResolveInfo::Function) &&
3537b74a387bb3993387029859c2d9d051c41c724eStephen Hines       ((pReloc.symValue() & 0x1) != 0))
3637b74a387bb3993387029859c2d9d051c41c724eStephen Hines          ? 1
3737b74a387bb3993387029859c2d9d051c41c724eStephen Hines          : 0;
3887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return thumbBit;
3987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
4087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
4187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// Using uint64_t to make sure those complicate operations won't cause
4287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// undefined behavior.
4337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width) {
4487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  assert(pOri_width <= 64);
4587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (pOri_width == 64)
4687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    return pVal;
4787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
4887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint64_t mask = (~((uint64_t)0)) >> (64 - pOri_width);
4987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pVal &= mask;
5087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // Reverse sign bit, then subtract sign bit.
5187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint64_t sign_bit = 1 << (pOri_width - 1);
5287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return (pVal ^ sign_bit) - sign_bit;
5387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
5487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
5537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask) {
5637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return (pA & ~pMask) | (pB & pMask);
5787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
5887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
5987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// Check if symbol can use relocation R_ARM_RELATIVE
6037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic bool helper_use_relative_reloc(const ResolveInfo& pSym,
6137b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                      const ARMRelocator& pFactory) {
6287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // if symbol is dynamic or undefine or preemptible
6337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (pSym.isDyn() || pSym.isUndef() ||
6487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      pFactory.getTarget().isSymbolPreemptible(pSym))
6587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    return false;
6687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return true;
6787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
6887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
6987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// Strip LSB (THUMB bit) if "S" is a THUMB target.
7037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic inline void helper_clear_thumb_bit(Relocator::DWord& pValue) {
7187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pValue &= (~0x1);
7287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
7387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
7437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::Address helper_get_GOT_address(ResolveInfo& pSym,
7537b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                                 ARMRelocator& pParent) {
7687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(pSym);
7737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(got_entry != NULL);
7887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return pParent.getTarget().getGOT().addr() + got_entry->getOffset();
7987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
8087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
8137b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic ARMGOTEntry& helper_GOT_init(Relocation& pReloc,
8237b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                    bool pHasRel,
8337b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                    ARMRelocator& pParent) {
8487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // rsym - The relocation target symbol
8587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ResolveInfo* rsym = pReloc.symInfo();
8687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGNULDBackend& ld_backend = pParent.getTarget();
8737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(pParent.getSymGOTMap().lookUp(*rsym) == NULL);
8887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
8987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGOTEntry* got_entry = ld_backend.getGOT().createGOT();
9087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pParent.getSymGOTMap().record(*rsym, *got_entry);
9187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // If we first get this GOT entry, we should initialize it.
9287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (!pHasRel) {
9387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    // No corresponding dynamic relocation, initialize to the symbol value.
9487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    got_entry->setValue(ARMRelocator::SymVal);
9537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else {
9687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    // Initialize corresponding dynamic relocation.
9787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    Relocation& rel_entry = *ld_backend.getRelDyn().create();
9887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    if (rsym->isLocal() || helper_use_relative_reloc(*rsym, pParent)) {
9987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      // Initialize got entry to target symbol address
10087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      got_entry->setValue(ARMRelocator::SymVal);
10187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
10287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      rel_entry.setSymInfo(NULL);
10337b74a387bb3993387029859c2d9d051c41c724eStephen Hines    } else {
10487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      // Initialize got entry to 0 for corresponding dynamic relocation.
10587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      got_entry->setValue(0);
10687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
10787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      rel_entry.setSymInfo(rsym);
10887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    }
10987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    rel_entry.targetRef().assign(*got_entry);
11087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
11187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return *got_entry;
11287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
11387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
11437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::Address helper_GOT_ORG(ARMRelocator& pParent) {
11587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return pParent.getTarget().getGOT().addr();
11687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
11787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
11837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::Address helper_get_PLT_address(ResolveInfo& pSym,
11937b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                                 ARMRelocator& pParent) {
12087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMPLT1* plt_entry = pParent.getSymPLTMap().lookUp(pSym);
12137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(plt_entry != NULL);
12287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return pParent.getTarget().getPLT().addr() + plt_entry->getOffset();
12387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
12487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
12537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic ARMPLT1& helper_PLT_init(Relocation& pReloc, ARMRelocator& pParent) {
12687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // rsym - The relocation target symbol
12787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ResolveInfo* rsym = pReloc.symInfo();
12887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGNULDBackend& ld_backend = pParent.getTarget();
12937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(pParent.getSymPLTMap().lookUp(*rsym) == NULL);
13087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
13187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // initialize the plt and the corresponding gotplt and dyn relocation
13287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMPLT1* plt_entry = ld_backend.getPLT().create();
13387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pParent.getSymPLTMap().record(*rsym, *plt_entry);
13487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
13537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(pParent.getSymGOTPLTMap().lookUp(*rsym) == NULL &&
13687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines         "PLT entry not exist, but DynRel entry exist!");
13787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGOTEntry* gotplt_entry = ld_backend.getGOT().createGOTPLT();
13887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
13987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
14087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  Relocation& rel_entry = *ld_backend.getRelPLT().create();
14187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
14287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  rel_entry.targetRef().assign(*gotplt_entry);
14387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  rel_entry.setSymInfo(rsym);
14487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
14587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return *plt_entry;
14687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
14787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
14887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// Get an relocation entry in .rel.dyn and set its type to pType,
14987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to
15087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// pReloc->symInfo()
15137b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic void helper_DynRel_init(Relocation& pReloc,
15237b74a387bb3993387029859c2d9d051c41c724eStephen Hines                               Relocator::Type pType,
15337b74a387bb3993387029859c2d9d051c41c724eStephen Hines                               ARMRelocator& pParent) {
15487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // rsym - The relocation target symbol
15587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ResolveInfo* rsym = pReloc.symInfo();
15687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGNULDBackend& ld_backend = pParent.getTarget();
15787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
15887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  Relocation& rel_entry = *ld_backend.getRelDyn().create();
15987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  rel_entry.setType(pType);
16087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  rel_entry.targetRef() = pReloc.targetRef();
16187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
16287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (pType == llvm::ELF::R_ARM_RELATIVE)
16387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    rel_entry.setSymInfo(NULL);
16487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  else
16587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    rel_entry.setSymInfo(rsym);
16687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
16787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
16837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_extract_movw_movt_addend(
16937b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pTarget) {
17087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // imm16: [19-16][11-0]
17187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
17287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines                            16);
17387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
17487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
17537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_insert_val_movw_movt_inst(
17637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pTarget,
17737b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pImm) {
17887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // imm16: [19-16][11-0]
17987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pTarget &= 0xfff0f000U;
18087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pTarget |= pImm & 0x0fffU;
18187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pTarget |= (pImm & 0xf000U) << 4;
18287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return pTarget;
18387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
18487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
18537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_extract_thumb_movw_movt_addend(
18637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pValue) {
18787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // imm16: [19-16][26][14-12][7-0]
18837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return helper_sign_extend(
18937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      (((pValue >> 4) & 0xf000U) | ((pValue >> 15) & 0x0800U) |
19037b74a387bb3993387029859c2d9d051c41c724eStephen Hines       ((pValue >> 4) & 0x0700U) | (pValue & 0x00ffU)),
19137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      16);
19287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
19387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
19437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_insert_val_thumb_movw_movt_inst(
19537b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pValue,
19637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pImm) {
19787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // imm16: [19-16][26][14-12][7-0]
19887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pValue &= 0xfbf08f00U;
19987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pValue |= (pImm & 0xf000U) << 4;
20087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pValue |= (pImm & 0x0800U) << 15;
20187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pValue |= (pImm & 0x0700U) << 4;
20287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  pValue |= (pImm & 0x00ffU);
20387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return pValue;
20487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
20587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
20637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_thumb32_branch_offset(
20737b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pUpper16,
20837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pLower16) {
20937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord s = (pUpper16 & (1U << 10)) >> 10,  // 26 bit
21037b74a387bb3993387029859c2d9d051c41c724eStephen Hines      u = pUpper16 & 0x3ffU,                           // 25-16
21137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      l = pLower16 & 0x7ffU,                           // 10-0
21237b74a387bb3993387029859c2d9d051c41c724eStephen Hines      j1 = (pLower16 & (1U << 13)) >> 13,              // 13
21337b74a387bb3993387029859c2d9d051c41c724eStephen Hines      j2 = (pLower16 & (1U << 11)) >> 11;              // 11
21437b74a387bb3993387029859c2d9d051c41c724eStephen Hines
21537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord i1 = j1 ^ s ? 0 : 1, i2 = j2 ^ s ? 0 : 1;
21687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
21787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // [31-25][24][23][22][21-12][11-1][0]
21887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  //      0   s  i1  i2      u     l  0
21937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return helper_sign_extend(
22037b74a387bb3993387029859c2d9d051c41c724eStephen Hines      (s << 24) | (i1 << 23) | (i2 << 22) | (u << 12) | (l << 1), 25);
22187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
22287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
22337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_thumb32_branch_upper(Relocator::DWord pUpper16,
22437b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                                    Relocator::DWord pOffset) {
22587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t sign = ((pOffset & 0x80000000U) >> 31);
22687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
22787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
22887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
22937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_thumb32_branch_lower(Relocator::DWord pLower16,
23037b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                                    Relocator::DWord pOffset) {
23187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t sign = ((pOffset & 0x80000000U) >> 31);
23237b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return ((pLower16 & ~0x2fffU) | ((((pOffset >> 23) & 1) ^ !sign) << 13) |
23337b74a387bb3993387029859c2d9d051c41c724eStephen Hines          ((((pOffset >> 22) & 1) ^ !sign) << 11) | ((pOffset >> 1) & 0x7ffU));
23487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
23587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
23637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_thumb32_cond_branch_offset(
23737b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pUpper16,
23837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pLower16) {
23987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t s = (pUpper16 & 0x0400U) >> 10;
24087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t j1 = (pLower16 & 0x2000U) >> 13;
24187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t j2 = (pLower16 & 0x0800U) >> 11;
24287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t lower = (pLower16 & 0x07ffU);
24387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t upper = (s << 8) | (j2 << 7) | (j1 << 6) | (pUpper16 & 0x003fU);
24487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return helper_sign_extend((upper << 12) | (lower << 1), 21);
24587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
24687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
24737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_thumb32_cond_branch_upper(
24837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pUpper16,
24937b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pOffset) {
25087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t sign = ((pOffset & 0x80000000U) >> 31);
25187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return (pUpper16 & 0xfbc0U) | (sign << 10) | ((pOffset & 0x0003f000U) >> 12);
25287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
25387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
25437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic Relocator::DWord helper_thumb32_cond_branch_lower(
25537b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pLower16,
25637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    Relocator::DWord pOffset) {
25787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t j2 = (pOffset & 0x00080000U) >> 19;
25887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t j1 = (pOffset & 0x00040000U) >> 18;
25987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint32_t lo = (pOffset & 0x00000ffeU) >> 1;
26087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  return (pLower16 & 0xd000U) | (j1 << 13) | (j2 << 11) | lo;
26187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
26287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
26387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// Return true if overflow
26437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic bool helper_check_signed_overflow(Relocator::DWord pValue,
26537b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                         unsigned bits) {
26687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  int32_t signed_val = static_cast<int32_t>(pValue);
26787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  int32_t max = (1 << (bits - 1)) - 1;
26887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  int32_t min = -(1 << (bits - 1));
26987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (signed_val > max || signed_val < min) {
27087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    return true;
27187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  } else {
27287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    return false;
27387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
27487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
27587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
27637b74a387bb3993387029859c2d9d051c41c724eStephen Hines//===----------------------------------------------------------------------===//
27767e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// Relocation Functions and Tables
27837b74a387bb3993387029859c2d9d051c41c724eStephen Hines//===----------------------------------------------------------------------===//
2795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei LiaoDECL_ARM_APPLY_RELOC_FUNCS
2805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
28167e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao/// the prototype of applying function
282d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liaotypedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
283d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao                                               ARMRelocator& pParent);
28467e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao
28567e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// the table entry of applying functions
28637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstruct ApplyFunctionTriple {
28767e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  ApplyFunctionType func;
28867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  unsigned int type;
28967e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  const char* name;
29067e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao};
29167e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao
29267e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// declare the table of applying functions
29367e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liaostatic const ApplyFunctionTriple ApplyFunctions[] = {
29437b74a387bb3993387029859c2d9d051c41c724eStephen Hines    DECL_ARM_APPLY_RELOC_FUNC_PTRS};
29567e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao
29637b74a387bb3993387029859c2d9d051c41c724eStephen Hines//===----------------------------------------------------------------------===//
297d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao// ARMRelocator
29837b74a387bb3993387029859c2d9d051c41c724eStephen Hines//===----------------------------------------------------------------------===//
299f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen HinesARMRelocator::ARMRelocator(ARMGNULDBackend& pParent,
300f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                           const LinkerConfig& pConfig)
30137b74a387bb3993387029859c2d9d051c41c724eStephen Hines    : Relocator(pConfig), m_Target(pParent) {
3025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
3035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
30437b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::~ARMRelocator() {
3055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
3065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
30737b74a387bb3993387029859c2d9d051c41c724eStephen HinesRelocator::Result ARMRelocator::applyRelocation(Relocation& pRelocation) {
3085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  Relocation::Type type = pRelocation.type();
30937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (type > 130) {  // 131-255 doesn't noted in ARM spec
310d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao    return Relocator::Unknown;
3115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
3125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
31322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return ApplyFunctions[type].func(pRelocation, *this);
3145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
3155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
31637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesconst char* ARMRelocator::getName(Relocator::Type pType) const {
31767e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  return ApplyFunctions[pType].name;
31867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao}
3195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
32037b74a387bb3993387029859c2d9d051c41c724eStephen HinesRelocator::Size ARMRelocator::getSize(Relocation::Type pType) const {
3216f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  return 32;
3226f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
3236f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
32437b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid ARMRelocator::addCopyReloc(ResolveInfo& pSym) {
32587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  Relocation& rel_entry = *getTarget().getRelDyn().create();
326f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  rel_entry.setType(llvm::ELF::R_ARM_COPY);
327f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  assert(pSym.outSymbol()->hasFragRef());
328f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
329f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  rel_entry.setSymInfo(&pSym);
330f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
331f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
332f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// defineSymbolForCopyReloc
333f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// For a symbol needing copy relocation, define a copy symbol in the BSS
334f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// section and all other reference to this symbol should refer to this
335f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// copy.
336f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// This is executed at scan relocation stage.
33737b74a387bb3993387029859c2d9d051c41c724eStephen HinesLDSymbol& ARMRelocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
33837b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                                 const ResolveInfo& pSym) {
339f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // get or create corresponding BSS LDSection
340f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  LDSection* bss_sect_hdr = NULL;
341f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  ELFFileFormat* file_format = getTarget().getOutputFormat();
342f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (ResolveInfo::ThreadLocal == pSym.type())
343f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    bss_sect_hdr = &file_format->getTBSS();
344f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  else
345f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    bss_sect_hdr = &file_format->getBSS();
346f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
347f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // get or create corresponding BSS SectionData
348f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  SectionData* bss_data = NULL;
349f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (bss_sect_hdr->hasSectionData())
350f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    bss_data = bss_sect_hdr->getSectionData();
351f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  else
352f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    bss_data = IRBuilder::CreateSectionData(*bss_sect_hdr);
353f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
354f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // Determine the alignment by the symbol value
355f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // FIXME: here we use the largest alignment
356f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  uint32_t addralign = config().targets().bitclass() / 8;
357f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
358f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // allocate space in BSS for the copy symbol
359f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  Fragment* frag = new FillFragment(0x0, 1, pSym.size());
36037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_data, addralign);
361f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
362f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
363f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // change symbol binding to Global if it's a weak symbol
364f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
365f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (binding == ResolveInfo::Weak)
366f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    binding = ResolveInfo::Global;
367f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
368f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // Define the copy symbol in the bss section and resolve it
369f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
37037b74a387bb3993387029859c2d9d051c41c724eStephen Hines      pSym.name(),
37137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      (ResolveInfo::Type)pSym.type(),
37237b74a387bb3993387029859c2d9d051c41c724eStephen Hines      ResolveInfo::Define,
37337b74a387bb3993387029859c2d9d051c41c724eStephen Hines      binding,
37437b74a387bb3993387029859c2d9d051c41c724eStephen Hines      pSym.size(),  // size
37537b74a387bb3993387029859c2d9d051c41c724eStephen Hines      0x0,          // value
37637b74a387bb3993387029859c2d9d051c41c724eStephen Hines      FragmentRef::Create(*frag, 0x0),
37737b74a387bb3993387029859c2d9d051c41c724eStephen Hines      (ResolveInfo::Visibility)pSym.other());
378f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  return *cpy_sym;
379f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
380f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
381f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// checkValidReloc - When we attempt to generate a dynamic relocation for
382f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// ouput file, check if the relocation is supported by dynamic linker.
38337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid ARMRelocator::checkValidReloc(Relocation& pReloc) const {
384f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // If not PIC object, no relocation type is invalid
385f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (!config().isCodeIndep())
386f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    return;
387f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
38837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  switch (pReloc.type()) {
389f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_RELATIVE:
390f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_COPY:
391f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GLOB_DAT:
392f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_JUMP_SLOT:
393f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS32:
394f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS32_NOI:
395f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_PC24:
396f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TLS_DTPMOD32:
397f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TLS_DTPOFF32:
398f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TLS_TPOFF32:
399f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      break;
400f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
401f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    default:
40237b74a387bb3993387029859c2d9d051c41c724eStephen Hines      error(diag::non_pic_relocation) << getName(pReloc.type())
403f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                      << pReloc.symInfo()->name();
404f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      break;
405f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  }
406f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
407f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
40837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesbool ARMRelocator::mayHaveFunctionPointerAccess(
40937b74a387bb3993387029859c2d9d051c41c724eStephen Hines    const Relocation& pReloc) const {
4100dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  switch (pReloc.type()) {
4110dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_PC24:
4120dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_THM_CALL:
4130dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_PLT32:
4140dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_CALL:
4150dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_JUMP24:
4160dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP24:
4170dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_SBREL31:
4180dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_PREL31:
4190dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP19:
4200dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP6:
4210dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP11:
4220dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP8: {
4230dea6bc96bb52346737966839ac68644f7939f58Stephen Hines      return false;
4240dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    }
42537b74a387bb3993387029859c2d9d051c41c724eStephen Hines    default: { return true; }
4260dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  }
4270dea6bc96bb52346737966839ac68644f7939f58Stephen Hines}
4280dea6bc96bb52346737966839ac68644f7939f58Stephen Hines
42937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid ARMRelocator::scanLocalReloc(Relocation& pReloc,
43037b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                  const LDSection& pSection) {
431f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // rsym - The relocation target symbol
432f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  ResolveInfo* rsym = pReloc.symInfo();
433f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
43437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  switch (pReloc.type()) {
435f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // Set R_ARM_TARGET1 to R_ARM_ABS32
436f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // FIXME: R_ARM_TARGET1 should be set by option --target1-rel
437f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // or --target1-rel
438f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TARGET1:
43937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      pReloc.setType(llvm::ELF::R_ARM_ABS32);
440f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS32:
441f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS32_NOI: {
442f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // If buiding PIC object (shared library or PIC executable),
443f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // a dynamic relocations with RELATIVE type to this location is needed.
444f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // Reserve an entry in .rel.dyn
445f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (config().isCodeIndep()) {
44687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines        helper_DynRel_init(pReloc, llvm::ELF::R_ARM_RELATIVE, *this);
447f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        // set Rel bit
448f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        rsym->setReserved(rsym->reserved() | ReserveRel);
449f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        getTarget().checkAndSetHasTextRel(*pSection.getLink());
450f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
451f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
452f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
453f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
454f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS16:
455f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS12:
456f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_ABS5:
457f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS8:
458f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_BASE_ABS:
459f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVW_ABS_NC:
460f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVT_ABS:
461f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
462f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVT_ABS: {
463f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // PIC code should not contain these kinds of relocation
464f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (config().isCodeIndep()) {
46537b74a387bb3993387029859c2d9d051c41c724eStephen Hines        error(diag::non_pic_relocation) << getName(pReloc.type())
466f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                        << pReloc.symInfo()->name();
467f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
468f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
469f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
470f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOTOFF32:
471f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOTOFF12: {
472f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // FIXME: A GOT section is needed
473f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
474f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
475f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
476f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
477f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // FIXME: R_ARM_TARGET2 should be set by option --target2
478f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TARGET2:
479f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
480f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOT_BREL:
481f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOT_PREL: {
482f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // A GOT entry is needed for these relocation type.
483f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // return if we already create GOT for this symbol
48487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      if (rsym->reserved() & ReserveGOT)
485f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return;
48687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
487f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // If building PIC object, a dynamic relocation with
488f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // type RELATIVE is needed to relocate this GOT entry.
48987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      if (config().isCodeIndep())
49037b74a387bb3993387029859c2d9d051c41c724eStephen Hines        helper_GOT_init(pReloc, true, *this);
49187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      else
49237b74a387bb3993387029859c2d9d051c41c724eStephen Hines        helper_GOT_init(pReloc, false, *this);
493f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // set GOT bit
49487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      rsym->setReserved(rsym->reserved() | ReserveGOT);
495f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
496f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
497f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
498f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_BASE_PREL: {
499f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // FIXME: Currently we only support R_ARM_BASE_PREL against
500f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // symbol _GLOBAL_OFFSET_TABLE_
501f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (rsym != getTarget().getGOTSymbol()->resolveInfo())
50237b74a387bb3993387029859c2d9d051c41c724eStephen Hines        fatal(diag::base_relocation) << static_cast<int>(pReloc.type())
50337b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                     << rsym->name()
504f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                     << "mclinker@googlegroups.com";
505f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
506f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
507f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_COPY:
508f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GLOB_DAT:
509f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_JUMP_SLOT:
510f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_RELATIVE: {
511f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // These are relocation type for dynamic linker, shold not
512f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // appear in object file.
51337b74a387bb3993387029859c2d9d051c41c724eStephen Hines      fatal(diag::dynamic_relocation) << static_cast<int>(pReloc.type());
514f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      break;
515f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
51637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    default: { break; }
51737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  }  // end switch
518f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
519f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
520f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesvoid ARMRelocator::scanGlobalReloc(Relocation& pReloc,
521f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                   IRBuilder& pBuilder,
52237b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                   const LDSection& pSection) {
523f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // rsym - The relocation target symbol
524f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  ResolveInfo* rsym = pReloc.symInfo();
525f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
52637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  switch (pReloc.type()) {
527f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // Set R_ARM_TARGET1 to R_ARM_ABS32
528f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // FIXME: R_ARM_TARGET1 should be set by option --target1-rel
529f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // or --target1-rel
530f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TARGET1:
531f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      pReloc.setType(llvm::ELF::R_ARM_ABS32);
532f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS32:
533f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS16:
534f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS12:
535f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_ABS5:
536f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS8:
537f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_BASE_ABS:
538f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVW_ABS_NC:
539f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVT_ABS:
540f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
541f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVT_ABS:
542f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ABS32_NOI: {
543f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // Absolute relocation type, symbol may needs PLT entry or
544f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // dynamic relocation entry
545f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (getTarget().symbolNeedsPLT(*rsym)) {
546f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        // create plt for this symbol if it does not have one
54737b74a387bb3993387029859c2d9d051c41c724eStephen Hines        if (!(rsym->reserved() & ReservePLT)) {
548f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // Symbol needs PLT entry, we need to reserve a PLT entry
549f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // and the corresponding GOT and dynamic relocation entry
55087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines          // in .got and .rel.plt.
55187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines          helper_PLT_init(pReloc, *this);
552f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // set PLT bit
553f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          rsym->setReserved(rsym->reserved() | ReservePLT);
554f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
555f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
556f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
55737b74a387bb3993387029859c2d9d051c41c724eStephen Hines      if (getTarget()
55837b74a387bb3993387029859c2d9d051c41c724eStephen Hines              .symbolNeedsDynRel(
55937b74a387bb3993387029859c2d9d051c41c724eStephen Hines                  *rsym, (rsym->reserved() & ReservePLT), true)) {
560f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
561f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
562f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          addCopyReloc(*cpy_sym.resolveInfo());
56337b74a387bb3993387029859c2d9d051c41c724eStephen Hines        } else {
564f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          checkValidReloc(pReloc);
565f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // set Rel bit
56687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines          if (helper_use_relative_reloc(*rsym, *this))
56787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines            helper_DynRel_init(pReloc, llvm::ELF::R_ARM_RELATIVE, *this);
56887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines          else
56987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines            helper_DynRel_init(pReloc, pReloc.type(), *this);
570f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          rsym->setReserved(rsym->reserved() | ReserveRel);
571f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          getTarget().checkAndSetHasTextRel(*pSection.getLink());
572f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
573f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
574f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
575f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
576f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
577f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOTOFF32:
578f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOTOFF12: {
579f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // FIXME: A GOT section is needed
580f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
581f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
582f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
583f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_BASE_PREL:
584f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
585f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVW_BREL:
586f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVT_BREL:
587f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // FIXME: Currently we only support these relocations against
588f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // symbol _GLOBAL_OFFSET_TABLE_
589f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (rsym != getTarget().getGOTSymbol()->resolveInfo()) {
59037b74a387bb3993387029859c2d9d051c41c724eStephen Hines        fatal(diag::base_relocation) << static_cast<int>(pReloc.type())
59137b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                     << rsym->name()
592f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                     << "mclinker@googlegroups.com";
593f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
594f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_REL32:
595f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDR_PC_G0:
596f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_SBREL32:
597f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_PC8:
598f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVW_PREL_NC:
599f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVT_PREL:
600f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVW_PREL_NC:
601f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_MOVT_PREL:
602f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_ALU_PREL_11_0:
603f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_PC12:
604f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_REL32_NOI:
605f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_PC_G0_NC:
606f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_PC_G0:
607f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_PC_G1_NC:
608f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_PC_G1:
609f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_PC_G2:
610f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDR_PC_G1:
611f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDR_PC_G2:
612f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDRS_PC_G0:
613f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDRS_PC_G1:
614f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDRS_PC_G2:
615f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDC_PC_G0:
616f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDC_PC_G1:
617f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDC_PC_G2:
618f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_SB_G0_NC:
619f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_SB_G0:
620f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_SB_G1_NC:
621f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_SB_G1:
622f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_ALU_SB_G2:
623f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDR_SB_G0:
624f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDR_SB_G1:
625f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDR_SB_G2:
626f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDRS_SB_G0:
627f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDRS_SB_G1:
628f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDRS_SB_G2:
629f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDC_SB_G0:
630f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDC_SB_G1:
631f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_LDC_SB_G2:
632f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVW_BREL_NC:
633f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVT_BREL:
634f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_MOVW_BREL: {
635f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // Relative addressing relocation, may needs dynamic relocation
63637b74a387bb3993387029859c2d9d051c41c724eStephen Hines      if (getTarget()
63737b74a387bb3993387029859c2d9d051c41c724eStephen Hines              .symbolNeedsDynRel(
63837b74a387bb3993387029859c2d9d051c41c724eStephen Hines                  *rsym, (rsym->reserved() & ReservePLT), false)) {
639f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
640f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
641f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
642f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          addCopyReloc(*cpy_sym.resolveInfo());
64337b74a387bb3993387029859c2d9d051c41c724eStephen Hines        } else {
644f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          checkValidReloc(pReloc);
645f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // set Rel bit
64637b74a387bb3993387029859c2d9d051c41c724eStephen Hines          helper_DynRel_init(pReloc, pReloc.type(), *this);
647f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          rsym->setReserved(rsym->reserved() | ReserveRel);
648f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          getTarget().checkAndSetHasTextRel(*pSection.getLink());
649f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
650f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
651f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
652f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
653f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
654f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_PC24:
655f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_CALL:
656f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_PLT32:
657f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_CALL:
658f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_JUMP24:
659f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP24:
660f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_SBREL31:
661f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_PREL31:
662f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP19:
663f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP6:
664f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP11:
665f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_THM_JUMP8: {
666f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // These are branch relocation (except PREL31)
667f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // A PLT entry is needed when building shared library
668f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
669f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // return if we already create plt for this symbol
670f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (rsym->reserved() & ReservePLT)
671f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return;
672f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
673f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // if the symbol's value can be decided at link time, then no need plt
674f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (getTarget().symbolFinalValueIsKnown(*rsym))
675f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return;
676f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
677f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // if symbol is defined in the ouput file and it's not
678f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // preemptible, no need plt
679f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (rsym->isDefine() && !rsym->isDyn() &&
680f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          !getTarget().isSymbolPreemptible(*rsym)) {
681f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return;
682f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
683f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
684f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // Symbol needs PLT entry, we need to reserve a PLT entry
685f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // and the corresponding GOT and dynamic relocation entry
68687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      // in .got and .rel.plt.
68787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      helper_PLT_init(pReloc, *this);
688f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // set PLT bit
689f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      rsym->setReserved(rsym->reserved() | ReservePLT);
690f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
691f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
692f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
693f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
694f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // FIXME: R_ARM_TARGET2 should be set by option --target2
695f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_TARGET2:
696f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
697f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOT_BREL:
698f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOT_ABS:
699f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GOT_PREL: {
700f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // Symbol needs GOT entry, reserve entry in .got
701f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // return if we already create GOT for this symbol
70287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      if (rsym->reserved() & ReserveGOT)
703f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return;
704f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // if the symbol cannot be fully resolved at link time, then we need a
705f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // dynamic relocation
70687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      if (!getTarget().symbolFinalValueIsKnown(*rsym))
70787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines        helper_GOT_init(pReloc, true, *this);
70887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      else
70987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines        helper_GOT_init(pReloc, false, *this);
710f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // set GOT bit
711f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      rsym->setReserved(rsym->reserved() | ReserveGOT);
712f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      return;
713f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
714f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
715f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_COPY:
716f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_GLOB_DAT:
717f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_JUMP_SLOT:
718f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    case llvm::ELF::R_ARM_RELATIVE: {
719f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // These are relocation type for dynamic linker, shold not
720f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      // appear in object file.
72137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      fatal(diag::dynamic_relocation) << static_cast<int>(pReloc.type());
722f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      break;
723f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
72437b74a387bb3993387029859c2d9d051c41c724eStephen Hines    default: { break; }
72537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  }  // end switch
726f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
727f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
728f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesvoid ARMRelocator::scanRelocation(Relocation& pReloc,
729f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                  IRBuilder& pBuilder,
730f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                  Module& pModule,
73187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines                                  LDSection& pSection,
73237b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                  Input& pInput) {
733f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // rsym - The relocation target symbol
734f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  ResolveInfo* rsym = pReloc.symInfo();
73537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(rsym != NULL &&
736f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines         "ResolveInfo of relocation not set while scanRelocation");
737f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
73837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  assert(pSection.getLink() != NULL);
73937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
740f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    return;
741f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
742f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
743f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // entries should be created.
744f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // FIXME: Below judgements concern nothing about TLS related relocation
745f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
746f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // rsym is local
747f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (rsym->isLocal())
748f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    scanLocalReloc(pReloc, pSection);
749f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
750f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // rsym is external
751f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  else
752f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    scanGlobalReloc(pReloc, pBuilder, pSection);
753f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
754f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // check if we shoule issue undefined reference for the relocation target
755f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // symbol
756f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
75787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    issueUndefRef(pReloc, pSection, pInput);
7585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
7595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
76037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesuint32_t ARMRelocator::getDebugStringOffset(Relocation& pReloc) const {
76137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (pReloc.type() != llvm::ELF::R_ARM_ABS32)
76237b74a387bb3993387029859c2d9d051c41c724eStephen Hines    error(diag::unsupport_reloc_for_debug_string)
76337b74a387bb3993387029859c2d9d051c41c724eStephen Hines        << getName(pReloc.type()) << "mclinker@googlegroups.com";
76437b74a387bb3993387029859c2d9d051c41c724eStephen Hines
76537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (pReloc.symInfo()->type() == ResolveInfo::Section)
76637b74a387bb3993387029859c2d9d051c41c724eStephen Hines    return pReloc.target();
76737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  else
76837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    return pReloc.symInfo()->outSymbol()->fragRef()->offset() +
76937b74a387bb3993387029859c2d9d051c41c724eStephen Hines               pReloc.target() + pReloc.addend();
77037b74a387bb3993387029859c2d9d051c41c724eStephen Hines}
77137b74a387bb3993387029859c2d9d051c41c724eStephen Hines
77237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid ARMRelocator::applyDebugStringOffset(Relocation& pReloc,
77337b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                          uint32_t pOffset) {
77437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  pReloc.target() = pOffset;
77537b74a387bb3993387029859c2d9d051c41c724eStephen Hines}
77637b74a387bb3993387029859c2d9d051c41c724eStephen Hines
7775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//=========================================//
7785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// Each relocation function implementation //
7795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//=========================================//
7805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
7815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_NONE
78237b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result none(Relocation& pReloc, ARMRelocator& pParent) {
783551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
7845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
7855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
7865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_ABS32: (S + A) | T
78737b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result abs32(Relocation& pReloc, ARMRelocator& pParent) {
7885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
789551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
790551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A = pReloc.target() + pReloc.addend();
791551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord S = pReloc.symValue();
792f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
793f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
7945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
79537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  // If the flag of target section is not ALLOC, we will not scan this
79637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  // relocation
797affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // but perform static relocation. (e.g., applying .debug section)
79837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if ((llvm::ELF::SHF_ALLOC &
79937b74a387bb3993387029859c2d9d051c41c724eStephen Hines       pReloc.targetRef().frag()->getParent()->getSection().flag()) == 0) {
800affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    pReloc.target() = (S + A) | T;
801551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::OK;
802affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
803affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
804affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // An external symbol may need PLT and dynamic relocation
805affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (!rsym->isLocal()) {
806f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (rsym->reserved() & ARMRelocator::ReservePLT) {
80787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      S = helper_get_PLT_address(*rsym, pParent);
80837b74a387bb3993387029859c2d9d051c41c724eStephen Hines      T = 0;  // PLT is not thumb
8095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
8105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    // If we generate a dynamic relocation (except R_ARM_RELATIVE)
8115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    // for a place, we should not perform static relocation on it
8125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    // in order to keep the addend store in the place correct.
81387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    if ((rsym->reserved() & ARMRelocator::ReserveRel) &&
81487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines        (!helper_use_relative_reloc(*rsym, pParent)))
815551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines      return Relocator::OK;
8165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
8175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8185460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // perform static relocation
8195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = (S + A) | T;
820551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
8215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
8225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_REL32: ((S + A) | T) - P
82437b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result rel32(Relocation& pReloc, ARMRelocator& pParent) {
8255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // perform static relocation
826551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
82737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord T = getThumbBit(pReloc);
82837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A = pReloc.target() + pReloc.addend();
82922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
83087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // An external symbol may need PLT (this reloc is from a stub/veneer)
83122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (!pReloc.symInfo()->isLocal()) {
832f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
83387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
83422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao      T = 0;  // PLT is not thumb.
83522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    }
83622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
83722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
83887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (T != 0x0)
83987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    helper_clear_thumb_bit(S);
84087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
84122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // perform relocation
84222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  pReloc.target() = ((S + A) | T) - pReloc.place();
84322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
844551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
8455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
8465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_BASE_PREL: B(S) + A - P
84837b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result base_prel(Relocation& pReloc, ARMRelocator& pParent) {
8495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // perform static relocation
850551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A = pReloc.target() + pReloc.addend();
85122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  pReloc.target() = pReloc.symValue() + A - pReloc.place();
852551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
8535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
8545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_GOTOFF32: ((S + A) | T) - GOT_ORG
85637b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result gotoff32(Relocation& pReloc, ARMRelocator& pParent) {
857551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
858551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A = pReloc.target() + pReloc.addend();
859551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
860551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
861f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
862f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
8635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = ((S + A) | T) - GOT_ORG;
865551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
8665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
8675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
86937b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result got_brel(Relocation& pReloc, ARMRelocator& pParent) {
87087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (!(pReloc.symInfo()->reserved() & ARMRelocator::ReserveGOT))
871551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::BadReloc;
87287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
873551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
87437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A = pReloc.target() + pReloc.addend();
875551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
8765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // Apply relocation.
8775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = GOT_S + A - GOT_ORG;
87887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
87987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // setup got entry value if needed
88087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
88137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (got_entry != NULL && ARMRelocator::SymVal == got_entry->getValue())
88287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    got_entry->setValue(pReloc.symValue());
883551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
8845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
8855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
8865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_GOT_PREL: GOT(S) + A - P
88737b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result got_prel(Relocation& pReloc, ARMRelocator& pParent) {
88887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (!(pReloc.symInfo()->reserved() & ARMRelocator::ReserveGOT)) {
889551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::BadReloc;
8905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
891551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
89237b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A = pReloc.target() + pReloc.addend();
89337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::Address P = pReloc.place();
89422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
8955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // Apply relocation.
8965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = GOT_S + A - P;
89787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
89887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // setup got entry value if needed
89987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
90037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (got_entry != NULL && ARMRelocator::SymVal == got_entry->getValue())
90187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    got_entry->setValue(pReloc.symValue());
902551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
9035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
9045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
9050dea6bc96bb52346737966839ac68644f7939f58Stephen Hines// R_ARM_THM_JUMP8: S + A - P
90637b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_jump8(Relocation& pReloc, ARMRelocator& pParent) {
9070dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  Relocator::DWord P = pReloc.place();
90837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A =
90937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_sign_extend((pReloc.target() & 0x00ff) << 1, 8) + pReloc.addend();
9100dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  // S depends on PLT exists or not
9110dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  Relocator::Address S = pReloc.symValue();
9120dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)
9130dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
9140dea6bc96bb52346737966839ac68644f7939f58Stephen Hines
9150dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  Relocator::DWord X = S + A - P;
9160dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  if (helper_check_signed_overflow(X, 9))
9170dea6bc96bb52346737966839ac68644f7939f58Stephen Hines    return Relocator::Overflow;
9180dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  //                    Make sure the Imm is 0.          Result Mask.
9190dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  pReloc.target() = (pReloc.target() & 0xFFFFFF00u) | ((X & 0x01FEu) >> 1);
9200dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  return Relocator::OK;
9210dea6bc96bb52346737966839ac68644f7939f58Stephen Hines}
9220dea6bc96bb52346737966839ac68644f7939f58Stephen Hines
923f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// R_ARM_THM_JUMP11: S + A - P
92437b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_jump11(Relocation& pReloc, ARMRelocator& pParent) {
925551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
92637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A =
92737b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_sign_extend((pReloc.target() & 0x07ff) << 1, 11) + pReloc.addend();
928f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // S depends on PLT exists or not
929551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
930f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)
93187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
932f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
933551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = S + A - P;
9340dea6bc96bb52346737966839ac68644f7939f58Stephen Hines  if (helper_check_signed_overflow(X, 12))
935551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
936f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //                    Make sure the Imm is 0.          Result Mask.
937f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  pReloc.target() = (pReloc.target() & 0xFFFFF800u) | ((X & 0x0FFEu) >> 1);
938551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
939f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
940f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
94187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines// R_ARM_THM_JUMP19: ((S + A) | T) - P
94237b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_jump19(Relocation& pReloc, ARMRelocator& pParent) {
94387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // get lower and upper 16 bit instructions from relocation targetData
94487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
94587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
94687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
947551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
94837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A =
94937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_thumb32_cond_branch_offset(upper_inst, lower_inst);
950551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address P = pReloc.place();
951551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S;
95287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  // if symbol has plt
95387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
95487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
95587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    T = 0;  // PLT is not thumb.
95637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else {
95787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    S = pReloc.symValue();
95887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    if (T != 0x0)
95987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      helper_clear_thumb_bit(S);
96087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
96187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
96237b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (T == 0x0) {
96387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    // FIXME: conditional branch to PLT in THUMB-2 not supported yet
96437b74a387bb3993387029859c2d9d051c41c724eStephen Hines    error(diag::unsupported_cond_branch_reloc)
96537b74a387bb3993387029859c2d9d051c41c724eStephen Hines        << static_cast<int>(pReloc.type());
966551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::BadReloc;
96787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  }
96887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
969551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = ((S + A) | T) - P;
97087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  if (helper_check_signed_overflow(X, 21))
971551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
97287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
97387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  upper_inst = helper_thumb32_cond_branch_upper(upper_inst, X);
97487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  lower_inst = helper_thumb32_cond_branch_lower(lower_inst, X);
97587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
97687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
97787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
97887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
979551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
98087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines}
98187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines
982f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// R_ARM_PC24: ((S + A) | T) - P
9835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_PLT32: ((S + A) | T) - P
9845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_JUMP24: ((S + A) | T) - P
9855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_CALL: ((S + A) | T) - P
98637b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result call(Relocation& pReloc, ARMRelocator& pParent) {
9875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // If target is undefined weak symbol, we only need to jump to the
988affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // next instruction unless it has PLT entry. Rewrite instruction
989affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // to NOP.
99037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
991affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      !pReloc.symInfo()->isDyn() &&
992f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      !(pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)) {
9935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    // change target to NOP : mov r0, r0
9945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
995551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::OK;
9965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
9975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
99837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord T = getThumbBit(pReloc);
99937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocator::DWord A =
100037b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26) +
100137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      pReloc.addend();
1002551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address P = pReloc.place();
1003551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1004f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1005f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
10065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1007f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // S depends on PLT exists or not
1008f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
100987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
10105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    T = 0;  // PLT is not thumb.
10115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
10125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
101322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // At this moment (after relaxation), if the jump target is thumb instruction,
101422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // switch mode is needed, rewrite the instruction to BLX
101522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // FIXME: check if we can use BLX instruction (check from .ARM.attribute
101622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // CPU ARCH TAG, which should be ARMv5 or above)
1017affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (T != 0) {
101822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // cannot rewrite to blx for R_ARM_JUMP24
101922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    if (pReloc.type() == llvm::ELF::R_ARM_JUMP24)
1020551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines      return Relocator::BadReloc;
1021f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (pReloc.type() == llvm::ELF::R_ARM_PC24)
1022551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines      return Relocator::BadReloc;
102322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
102437b74a387bb3993387029859c2d9d051c41c724eStephen Hines    pReloc.target() =
102537b74a387bb3993387029859c2d9d051c41c724eStephen Hines        (pReloc.target() & 0xffffff) | 0xfa000000 | (((S + A - P) & 2) << 23);
10265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
1027affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
1028551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = ((S + A) | T) - P;
10295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // Check X is 24bit sign int. If not, we should use stub or PLT before apply.
103067e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  if (helper_check_signed_overflow(X, 26))
1031551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
10325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  //                    Make sure the Imm is 0.          Result Mask.
10335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = (pReloc.target() & 0xFF000000u) | ((X & 0x03FFFFFEu) >> 2);
1034551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
10355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
10365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
10375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_THM_CALL: ((S + A) | T) - P
1038f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// R_ARM_THM_JUMP24: ((S + A) | T) - P
103937b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_call(Relocation& pReloc, ARMRelocator& pParent) {
10405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // If target is undefined weak symbol, we only need to jump to the
1041affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // next instruction unless it has PLT entry. Rewrite instruction
1042affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // to NOP.
104337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
1044affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      !pReloc.symInfo()->isDyn() &&
1045f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      !(pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT)) {
10465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    pReloc.target() = (0xe000U << 16) | 0xbf00U;
1047551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::OK;
10485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
10495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1050affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // get lower and upper 16 bit instructions from relocation targetData
105122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
105222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
10535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1054551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1055551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A = helper_thumb32_branch_offset(upper_inst, lower_inst);
1056551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address P = pReloc.place();
1057551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S;
10585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
10595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // if symbol has plt
1060f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
106187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
10625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    T = 0;  // PLT is not thumb.
106337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else {
1064affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    S = pReloc.symValue();
1065f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (T != 0x0)
1066f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      helper_clear_thumb_bit(S);
1067affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
10685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1069affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  S = S + A;
10705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
107122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // At this moment (after relaxation), if the jump target is arm
107222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // instruction, switch mode is needed, rewrite the instruction to BLX
1073affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // FIXME: check if we can use BLX instruction (check from .ARM.attribute
1074affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // CPU ARCH TAG, which should be ARMv5 or above)
1075affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (T == 0) {
107622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // cannot rewrite to blx for R_ARM_THM_JUMP24
107722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    if (pReloc.type() == llvm::ELF::R_ARM_THM_JUMP24)
1078551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines      return Relocator::BadReloc;
107922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1080affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // for BLX, select bit 1 from relocation base address to jump target
1081affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // address
1082affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    S = helper_bit_select(S, P, 0x2);
1083affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // rewrite instruction to BLX
108422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    lower_inst &= ~0x1000U;
108537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else {
1086affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // otherwise, the instruction should be BL
108722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    lower_inst |= 0x1000U;
1088affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
1089affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
1090551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = (S | T) - P;
1091affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
10925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // FIXME: Check bit size is 24(thumb2) or 22?
1093affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (helper_check_signed_overflow(X, 25)) {
1094551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
10955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
10965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
109722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  upper_inst = helper_thumb32_branch_upper(upper_inst, X);
109822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  lower_inst = helper_thumb32_branch_lower(lower_inst, X);
10995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
110022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
110122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
11025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1103551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
11045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
11055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_MOVW_ABS_NC: (S + A) | T
110737b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent) {
11085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
1109551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1110551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1111551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
111237b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
1113f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1114f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
11155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
111622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
111722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
111867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  // If the flag of target section is not ALLOC, we will not scan this
111967e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  // relocation but perform static relocation. (e.g., applying .debug section)
112037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) != 0x0) {
1121affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // use plt
1122f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (rsym->reserved() & ARMRelocator::ReservePLT) {
112387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      S = helper_get_PLT_address(*rsym, pParent);
112437b74a387bb3993387029859c2d9d051c41c724eStephen Hines      T = 0;  // PLT is not thumb
1125affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
11265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
1127affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
11285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // perform static relocation
1129551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = (S + A) | T;
113037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  pReloc.target() =
113137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_insert_val_movw_movt_inst(pReloc.target() + pReloc.addend(), X);
1132551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
11335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
11345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_MOVW_PREL_NC: ((S + A) | T) - P
113637b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent) {
1137551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1138551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1139551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
1140551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
114137b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
1142f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1143f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
1144551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = ((S + A) | T) - P;
11455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  if (helper_check_signed_overflow(X, 16)) {
1147551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
11485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  } else {
11495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
1150551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::OK;
11515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
11525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
11535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_MOVT_ABS: S + A
115537b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result movt_abs(Relocation& pReloc, ARMRelocator& pParent) {
11565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
1157551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1158551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
115937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
11605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
116122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
116222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
116337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  // If the flag of target section is not ALLOC, we will not scan this
116437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  // relocation
1165affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // but perform static relocation. (e.g., applying .debug section)
116637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) != 0x0) {
1167affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // use plt
1168f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (rsym->reserved() & ARMRelocator::ReservePLT) {
116987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      S = helper_get_PLT_address(*rsym, pParent);
1170affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
11715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
11725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1173551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = S + A;
11745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  X >>= 16;
11755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // perform static relocation
11765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
1177551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
11785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
11795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_MOVT_PREL: S + A - P
118137b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result movt_prel(Relocation& pReloc, ARMRelocator& pParent) {
1182551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1183551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
1184551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
118537b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
1186551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = S + A - P;
11875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  X >>= 16;
11885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
1190551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
11915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
11925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_THM_MOVW_ABS_NC: (S + A) | T
119437b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_movw_abs_nc(Relocation& pReloc,
119537b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                     ARMRelocator& pParent) {
11965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
1197551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1198551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1199f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1200f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
120122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
120222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // get lower and upper 16 bit instructions from relocation targetData
120322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
120422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
1205551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord val = ((upper_inst) << 16) | (lower_inst);
1206551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
120737b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
12085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
120922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
121037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  // If the flag of target section is not ALLOC, we will not scan this
121137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  // relocation
1212affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // but perform static relocation. (e.g., applying .debug section)
121337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) != 0x0) {
1214affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // use plt
1215f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (rsym->reserved() & ARMRelocator::ReservePLT) {
121687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      S = helper_get_PLT_address(*rsym, pParent);
121737b74a387bb3993387029859c2d9d051c41c724eStephen Hines      T = 0;  // PLT is not thumb
1218affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
12195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
1220551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = (S + A) | T;
122122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
122222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  val = helper_insert_val_thumb_movw_movt_inst(val, X);
1223f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = val >> 16;
1224f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = val & 0xFFFFu;
122522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1226551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
12275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
12285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
12295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
123037b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_movw_prel_nc(Relocation& pReloc,
123137b74a387bb3993387029859c2d9d051c41c724eStephen Hines                                      ARMRelocator& pParent) {
1232551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1233551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1234551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
1235f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1236f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
123722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
123822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // get lower and upper 16 bit instructions from relocation targetData
123922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
124022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
1241551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord val = ((upper_inst) << 16) | (lower_inst);
1242551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
124337b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
1244551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = ((S + A) | T) - P;
12455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
124622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  val = helper_insert_val_thumb_movw_movt_inst(val, X);
1247f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = val >> 16;
1248f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = val & 0xFFFFu;
124922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1250551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
1251affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
1252affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
1253affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S)
1254affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S)
125537b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_movw_brel(Relocation& pReloc, ARMRelocator& pParent) {
1256551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1257551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1258551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
1259f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1260f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
126122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
126222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // get lower and upper 16 bit instructions from relocation targetData
126322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
126422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
1265551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord val = ((upper_inst) << 16) | (lower_inst);
1266551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
126737b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
1268affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
1269551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = ((S + A) | T) - P;
1270affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
127122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  val = helper_insert_val_thumb_movw_movt_inst(val, X);
1272f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = val >> 16;
1273f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = val & 0xFFFFu;
127422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1275551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
12765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
12775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
12785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_THM_MOVT_ABS: S + A
127937b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_movt_abs(Relocation& pReloc, ARMRelocator& pParent) {
12805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
1281551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
128222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
128322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // get lower and upper 16 bit instructions from relocation targetData
128422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
128522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
1286551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord val = ((upper_inst) << 16) | (lower_inst);
1287551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
128837b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
12895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
129022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
1291f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // If the flag of target section is not ALLOC, we will not scan this
1292f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // relocation but perform static relocation. (e.g., applying .debug section)
129337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if ((llvm::ELF::SHF_ALLOC & target_sect.flag()) != 0x0) {
1294affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // use plt
1295f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (rsym->reserved() & ARMRelocator::ReservePLT) {
129687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines      S = helper_get_PLT_address(*rsym, pParent);
1297affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
12985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
1299affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
1300551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = S + A;
13015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  X >>= 16;
13025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
13035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // check 16-bit overflow
1304f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (helper_check_signed_overflow(X, 16))
1305551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
1306f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  val = helper_insert_val_thumb_movw_movt_inst(val, X);
1307f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = val >> 16;
1308f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = val & 0xFFFFu;
1309551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
13105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
13115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
13125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_THM_MOVT_PREL: S + A - P
1313affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// R_ARM_THM_MOVT_BREL: S + A - B(S)
131437b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result thm_movt_prel(Relocation& pReloc, ARMRelocator& pParent) {
1315551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1316551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
131722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
131822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // get lower and upper 16 bit instructions from relocation targetData
131922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
132022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
1321551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord val = ((upper_inst) << 16) | (lower_inst);
1322551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A =
132337b74a387bb3993387029859c2d9d051c41c724eStephen Hines      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
1324551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = S + A - P;
13255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  X >>= 16;
132622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
132722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  val = helper_insert_val_thumb_movw_movt_inst(val, X);
1328f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = val >> 16;
1329f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = val & 0xFFFFu;
133022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
1331551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
13325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
13335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
133422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao// R_ARM_PREL31: ((S + A) | T) - P
133537b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result prel31(Relocation& pReloc, ARMRelocator& pParent) {
1336551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord target = pReloc.target();
1337551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord T = getThumbBit(pReloc);
1338551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord A = helper_sign_extend(target, 31) + pReloc.addend();
1339551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord P = pReloc.place();
1340551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::Address S = pReloc.symValue();
1341f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (T != 0x0)
1342f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    helper_clear_thumb_bit(S);
13435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
13445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // if symbol has plt
134537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (pReloc.symInfo()->reserved() & ARMRelocator::ReservePLT) {
134687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines    S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
13475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    T = 0;  // PLT is not thumb.
13485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
13495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1350551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  Relocator::DWord X = ((S + A) | T) - P;
13515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
1352affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (helper_check_signed_overflow(X, 31))
1353551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines    return Relocator::Overflow;
1354551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines  return Relocator::OK;
13555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
13565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
13575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_TLS_GD32: GOT(S) + A - P
13585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_TLS_IE32: GOT(S) + A - P
13595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_ARM_TLS_LE32: S + A - tp
136037b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result tls(Relocation& pReloc, ARMRelocator& pParent) {
136137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return Relocator::Unsupported;
13625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
13635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
136437b74a387bb3993387029859c2d9d051c41c724eStephen HinesARMRelocator::Result unsupported(Relocation& pReloc, ARMRelocator& pParent) {
136537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  return Relocator::Unsupported;
13665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
136737b74a387bb3993387029859c2d9d051c41c724eStephen Hines
136837b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace mcld
1369