void GarbageCollection::setUpReachedSections()
{
  // traverse all the input relocations to setup the reached sections
  Module::obj_iterator input, inEnd = m_Module.obj_end();
  for (input = m_Module.obj_begin(); input != inEnd; ++input) {
    LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
    for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
      // bypass the discarded relocation section
      // 1. its section kind is changed to Ignore. (The target section is a
      // discarded group section.)
      // 2. it has no reloc data. (All symbols in the input relocs are in the
      // discarded group sections)
      LDSection* reloc_sect = *rs;
      LDSection* apply_sect = reloc_sect->getLink();
      if ((LDFileFormat::Ignore == reloc_sect->kind()) ||
          (!reloc_sect->hasRelocData()))
        continue;

      // bypass the apply target sections which are not handled by gc (currently
      // we only handle the Regular and BSS sections)
      if (apply_sect->kind() != LDFileFormat::Regular &&
          apply_sect->kind() != LDFileFormat::BSS)
        continue;

      bool add_first = false;
      SectionListTy* reached_sects = NULL;
      RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end();
      for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd;
                                                                   ++reloc_it) {
        Relocation* reloc = llvm::cast<Relocation>(reloc_it);
        ResolveInfo* sym = reloc->symInfo();
        // only the target symbols defined in the input fragments can make the
        // reference
        if (NULL == sym)
          continue;
        if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
          continue;

        // only the target symbols defined in the concerned sections can make
        // the reference
        const LDSection* target_sect =
                &sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
        if (target_sect->kind() != LDFileFormat::Regular &&
            target_sect->kind() != LDFileFormat::BSS)
          continue;

        // setup the reached list, if we first add the element to reached list
        // of this section, create an entry in ReachedSections map
        if (!add_first) {
          assert(NULL == reached_sects);
          reached_sects = &m_ReachedSections[apply_sect];
          add_first = true;
        }
        reached_sects->insert(target_sect);
      }
      reached_sects = NULL;
      add_first = false;
    }
  }
}
TEST_F( StaticResolverTest, SetUpBinding)
{
  ResolveInfo* sym = ResolveInfo::Create("abc");
  
  sym->setIsSymbol(true);

//  ASSERT_FALSE( sym->isSymbol() );
  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setBinding(ResolveInfo::Global);
  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( ResolveInfo::Global == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setBinding(ResolveInfo::Weak);
  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_FALSE( sym->isGlobal() );
  ASSERT_TRUE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( ResolveInfo::Weak == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setBinding(ResolveInfo::Local);
  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_FALSE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_TRUE( sym->isLocal() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( ResolveInfo::Local == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );
}
TEST_F( StaticResolverTest, SetUpDesc)
{
  ResolveInfo* sym = ResolveInfo::Create("abc");
  
  sym->setIsSymbol(true);

//  ASSERT_FALSE( sym->isSymbol() );
  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setIsSymbol(false);
  ASSERT_FALSE( sym->isSymbol() );
//  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setDesc(ResolveInfo::Define);
  ASSERT_FALSE( sym->isSymbol() );
//  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_TRUE( sym->isDefine() );
  ASSERT_FALSE( sym->isUndef() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( ResolveInfo::Define == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setDesc(ResolveInfo::Common);
  ASSERT_FALSE( sym->isSymbol() );
//  ASSERT_TRUE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_FALSE( sym->isUndef() );
  ASSERT_TRUE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( ResolveInfo::Common == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setDesc(ResolveInfo::Indirect);
  ASSERT_FALSE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_FALSE( sym->isUndef() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_TRUE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( ResolveInfo::Indirect == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );

  sym->setDesc(ResolveInfo::Undefined);
  ASSERT_FALSE( sym->isSymbol() );
  ASSERT_TRUE( sym->isGlobal() );
  ASSERT_FALSE( sym->isWeak() );
  ASSERT_FALSE( sym->isLocal() );
  ASSERT_FALSE( sym->isDyn() );
  ASSERT_TRUE( sym->isUndef() );
  ASSERT_FALSE( sym->isDefine() );
  ASSERT_FALSE( sym->isCommon() );
  ASSERT_FALSE( sym->isIndirect() );
  ASSERT_TRUE( ResolveInfo::NoType == sym->type());
  ASSERT_TRUE( 0 == sym->desc() );
  ASSERT_TRUE( 0 == sym->binding() );
  ASSERT_TRUE( 0 == sym->other() );
}
void ARMGNULDBackend::scanGlobalReloc(Relocation& pReloc,
                                      const LDSymbol& pInputSym,
                                      MCLinker& pLinker,
                                      const MCLDInfo& pLDInfo,
                                      const Output& pOutput)
{
  // rsym - The relocation target symbol
  ResolveInfo* rsym = pReloc.symInfo();

  switch(pReloc.type()) {

    // Set R_ARM_TARGET1 to R_ARM_ABS32
    // Ref: GNU gold 1.11 arm.cc, line 9892
    case llvm::ELF::R_ARM_TARGET1:
      pReloc.setType(llvm::ELF::R_ARM_ABS32);
    case llvm::ELF::R_ARM_ABS32:
    case llvm::ELF::R_ARM_ABS16:
    case llvm::ELF::R_ARM_ABS12:
    case llvm::ELF::R_ARM_THM_ABS5:
    case llvm::ELF::R_ARM_ABS8:
    case llvm::ELF::R_ARM_BASE_ABS:
    case llvm::ELF::R_ARM_MOVW_ABS_NC:
    case llvm::ELF::R_ARM_MOVT_ABS:
    case llvm::ELF::R_ARM_THM_MOVW_ABS_NC:
    case llvm::ELF::R_ARM_THM_MOVT_ABS:
    case llvm::ELF::R_ARM_ABS32_NOI: {
      // Absolute relocation type, symbol may needs PLT entry or
      // dynamic relocation entry
      if(isSymbolNeedsPLT(*rsym, pLDInfo, pOutput)) {
        // create plt for this symbol if it does not have one
        if(!(rsym->reserved() & 0x8u)){
          // Create .got section if it doesn't exist
          if(NULL == m_pGOT)
            createARMGOT(pLinker, pOutput);
          // create .plt and .rel.plt if not exist
          if(NULL == m_pPLT)
            createARMPLTandRelPLT(pLinker, pOutput);
          // Symbol needs PLT entry, we need to reserve a PLT entry
          // and the corresponding GOT and dynamic relocation entry
          // in .got and .rel.plt. (GOT entry will be reserved simultaneously
          // when calling ARMPLT->reserveEntry())
          m_pPLT->reserveEntry();
          m_pRelPLT->reserveEntry(*m_pRelocFactory);
          // set PLT bit
          rsym->setReserved(rsym->reserved() | 0x8u);
        }
      }

      if(isSymbolNeedsDynRel(*rsym, pOutput, true)) {
        checkValidReloc(pReloc, pLDInfo, pOutput);
        // symbol needs dynamic relocation entry, reserve an entry in .rel.dyn
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set Rel bit
        rsym->setReserved(rsym->reserved() | 0x1u);
      }
      return;
    }

    case llvm::ELF::R_ARM_GOTOFF32:
    case llvm::ELF::R_ARM_GOTOFF12: {
      // A GOT section is needed
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);
      return;
    }

    case llvm::ELF::R_ARM_BASE_PREL:
      // FIXME: Currently we only support R_ARM_BASE_PREL against
      // symbol _GLOBAL_OFFSET_TABLE_
      if(rsym != m_pGOTSymbol->resolveInfo()) {
        llvm::report_fatal_error(llvm::Twine("Do not support relocation '") +
                                 llvm::Twine("R_ARM_BASE_PREL' against symbol '") +
                                 llvm::Twine(rsym->name()) +
                                 llvm::Twine(".'"));
      }
    case llvm::ELF::R_ARM_REL32:
    case llvm::ELF::R_ARM_LDR_PC_G0:
    case llvm::ELF::R_ARM_SBREL32:
    case llvm::ELF::R_ARM_THM_PC8:
    case llvm::ELF::R_ARM_MOVW_PREL_NC:
    case llvm::ELF::R_ARM_MOVT_PREL:
    case llvm::ELF::R_ARM_THM_MOVW_PREL_NC:
    case llvm::ELF::R_ARM_THM_MOVT_PREL:
    case llvm::ELF::R_ARM_THM_ALU_PREL_11_0:
    case llvm::ELF::R_ARM_THM_PC12:
    case llvm::ELF::R_ARM_REL32_NOI:
    case llvm::ELF::R_ARM_ALU_PC_G0_NC:
    case llvm::ELF::R_ARM_ALU_PC_G0:
    case llvm::ELF::R_ARM_ALU_PC_G1_NC:
    case llvm::ELF::R_ARM_ALU_PC_G1:
    case llvm::ELF::R_ARM_ALU_PC_G2:
    case llvm::ELF::R_ARM_LDR_PC_G1:
    case llvm::ELF::R_ARM_LDR_PC_G2:
    case llvm::ELF::R_ARM_LDRS_PC_G0:
    case llvm::ELF::R_ARM_LDRS_PC_G1:
    case llvm::ELF::R_ARM_LDRS_PC_G2:
    case llvm::ELF::R_ARM_LDC_PC_G0:
    case llvm::ELF::R_ARM_LDC_PC_G1:
    case llvm::ELF::R_ARM_LDC_PC_G2:
    case llvm::ELF::R_ARM_ALU_SB_G0_NC:
    case llvm::ELF::R_ARM_ALU_SB_G0:
    case llvm::ELF::R_ARM_ALU_SB_G1_NC:
    case llvm::ELF::R_ARM_ALU_SB_G1:
    case llvm::ELF::R_ARM_ALU_SB_G2:
    case llvm::ELF::R_ARM_LDR_SB_G0:
    case llvm::ELF::R_ARM_LDR_SB_G1:
    case llvm::ELF::R_ARM_LDR_SB_G2:
    case llvm::ELF::R_ARM_LDRS_SB_G0:
    case llvm::ELF::R_ARM_LDRS_SB_G1:
    case llvm::ELF::R_ARM_LDRS_SB_G2:
    case llvm::ELF::R_ARM_LDC_SB_G0:
    case llvm::ELF::R_ARM_LDC_SB_G1:
    case llvm::ELF::R_ARM_LDC_SB_G2:
    case llvm::ELF::R_ARM_MOVW_BREL_NC:
    case llvm::ELF::R_ARM_MOVT_BREL:
    case llvm::ELF::R_ARM_MOVW_BREL:
    case llvm::ELF::R_ARM_THM_MOVW_BREL_NC:
    case llvm::ELF::R_ARM_THM_MOVT_BREL:
    case llvm::ELF::R_ARM_THM_MOVW_BREL: {
      // Relative addressing relocation, may needs dynamic relocation
      if(isSymbolNeedsDynRel(*rsym, pOutput, false)) {
        checkValidReloc(pReloc, pLDInfo, pOutput);
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set Rel bit
        rsym->setReserved(rsym->reserved() | 0x1u);
      }
      return;
    }

    case llvm::ELF::R_ARM_THM_CALL:
    case llvm::ELF::R_ARM_PLT32:
    case llvm::ELF::R_ARM_CALL:
    case llvm::ELF::R_ARM_JUMP24:
    case llvm::ELF::R_ARM_THM_JUMP24:
    case llvm::ELF::R_ARM_SBREL31:
    case llvm::ELF::R_ARM_PREL31:
    case llvm::ELF::R_ARM_THM_JUMP19:
    case llvm::ELF::R_ARM_THM_JUMP6:
    case llvm::ELF::R_ARM_THM_JUMP11:
    case llvm::ELF::R_ARM_THM_JUMP8: {
      // These are branch relocation (except PREL31)
      // A PLT entry is needed when building shared library

      // return if we already create plt for this symbol
      if(rsym->reserved() & 0x8u)
        return;

      // if symbol is defined in the ouput file and it's not
      // preemptible, no need plt
      if(rsym->isDefine() && !rsym->isDyn() &&
         !isSymbolPreemptible(*rsym, pLDInfo, pOutput)) {
        return;
      }

      // Create .got section if it doesn't exist
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);

      // create .plt and .rel.plt if not exist
      if(NULL == m_pPLT)
         createARMPLTandRelPLT(pLinker, pOutput);
      // Symbol needs PLT entry, we need to reserve a PLT entry
      // and the corresponding GOT and dynamic relocation entry
      // in .got and .rel.plt. (GOT entry will be reserved simultaneously
      // when calling ARMPLT->reserveEntry())
      m_pPLT->reserveEntry();
      m_pRelPLT->reserveEntry(*m_pRelocFactory);
      // set PLT bit
      rsym->setReserved(rsym->reserved() | 0x8u);
      return;
    }

    // Set R_ARM_TARGET2 to R_ARM_GOT_PREL
    // Ref: GNU gold 1.11 arm.cc, line 9892
    case llvm::ELF::R_ARM_TARGET2:
      pReloc.setType(llvm::ELF::R_ARM_GOT_PREL);
    case llvm::ELF::R_ARM_GOT_BREL:
    case llvm::ELF::R_ARM_GOT_ABS:
    case llvm::ELF::R_ARM_GOT_PREL: {
      // Symbol needs GOT entry, reserve entry in .got
      // return if we already create GOT for this symbol
      if(rsym->reserved() & 0x6u)
        return;
      if(NULL == m_pGOT)
        createARMGOT(pLinker, pOutput);
      m_pGOT->reserveEntry();
      // If building shared object or the symbol is undefined, a dynamic
      // relocation is needed to relocate this GOT entry. Reserve an
      // entry in .rel.dyn
      if(Output::DynObj == pOutput.type() || rsym->isUndef() || rsym->isDyn()) {
        // create .rel.dyn section if not exist
        if(NULL == m_pRelDyn)
          createARMRelDyn(pLinker, pOutput);
        m_pRelDyn->reserveEntry(*m_pRelocFactory);
        // set GOTRel bit
        rsym->setReserved(rsym->reserved() | 0x4u);
        return;
      }
      // set GOT bit
      rsym->setReserved(rsym->reserved() | 0x2u);
      return;
    }

    case llvm::ELF::R_ARM_COPY:
    case llvm::ELF::R_ARM_GLOB_DAT:
    case llvm::ELF::R_ARM_JUMP_SLOT:
    case llvm::ELF::R_ARM_RELATIVE: {
      // These are relocation type for dynamic linker, shold not
      // appear in object file.
      llvm::report_fatal_error(llvm::Twine("Unexpected reloc ") +
                               llvm::Twine((int)pReloc.type()) +
                               llvm::Twine(" in object file"));
      break;
    }
    default: {
      break;
    }
  } // end switch
}
Exemplo n.º 5
0
void ARMGNULDBackend::setUpReachedSectionsForGC(const Module& pModule,
            GarbageCollection::SectionReachedListMap& pSectReachedListMap) const
{
  // traverse all the input relocations to find the relocation sections applying
  // .ARM.exidx sections
  Module::const_obj_iterator input, inEnd = pModule.obj_end();
  for (input = pModule.obj_begin(); input != inEnd; ++input) {
    LDContext::const_sect_iterator rs,
                                   rsEnd = (*input)->context()->relocSectEnd();
    for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
      // bypass the discarded relocation section
      // 1. its section kind is changed to Ignore. (The target section is a
      // discarded group section.)
      // 2. it has no reloc data. (All symbols in the input relocs are in the
      // discarded group sections)
      LDSection* reloc_sect = *rs;
      LDSection* apply_sect = reloc_sect->getLink();
      if ((LDFileFormat::Ignore == reloc_sect->kind()) ||
          (!reloc_sect->hasRelocData()))
        continue;

      if (llvm::ELF::SHT_ARM_EXIDX == apply_sect->type()) {
        // 1. set up the reference according to relocations
        bool add_first = false;
        GarbageCollection::SectionListTy* reached_sects = NULL;
        RelocData::iterator reloc_it, rEnd = reloc_sect->getRelocData()->end();
        for (reloc_it = reloc_sect->getRelocData()->begin(); reloc_it != rEnd;
                                                                   ++reloc_it) {
          Relocation* reloc = llvm::cast<Relocation>(reloc_it);
          ResolveInfo* sym = reloc->symInfo();
          // only the target symbols defined in the input fragments can make the
          // reference
          if (NULL == sym)
            continue;
          if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
            continue;

          // only the target symbols defined in the concerned sections can make
          // the reference
          const LDSection* target_sect =
                &sym->outSymbol()->fragRef()->frag()->getParent()->getSection();
          if (target_sect->kind() != LDFileFormat::TEXT &&
              target_sect->kind() != LDFileFormat::DATA &&
              target_sect->kind() != LDFileFormat::BSS)
            continue;

          // setup the reached list, if we first add the element to reached list
          // of this section, create an entry in ReachedSections map
          if (!add_first) {
            reached_sects = &pSectReachedListMap.getReachedList(*apply_sect);
            add_first = true;
          }
          reached_sects->insert(target_sect);
        }
        reached_sects = NULL;
        add_first = false;
        // 2. set up the reference from XXX to .ARM.exidx.XXX
        assert(apply_sect->getLink() != NULL);
        pSectReachedListMap.addReference(*apply_sect->getLink(), *apply_sect);
      }
    }
  }
}