C++程序  |  734行  |  25.15 KB

//===- ELFObjectWriter.cpp ------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/LD/ELFObjectWriter.h>

#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
#include <mcld/LinkerScript.h>
#include <mcld/Target/GNULDBackend.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/ADT/SizeTraits.h>
#include <mcld/Fragment/AlignFragment.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/Fragment/RegionFragment.h>
#include <mcld/Fragment/Stub.h>
#include <mcld/Fragment/NullFragment.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/ELFSegment.h>
#include <mcld/LD/ELFSegmentFactory.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/ELFFileFormat.h>
#include <mcld/Target/GNUInfo.h>

#include <llvm/Support/Errc.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/ELF.h>
#include <llvm/Support/Casting.h>

using namespace llvm;
using namespace llvm::ELF;
using namespace mcld;

//===----------------------------------------------------------------------===//
// ELFObjectWriter
//===----------------------------------------------------------------------===//
ELFObjectWriter::ELFObjectWriter(GNULDBackend& pBackend,
                                 const LinkerConfig& pConfig)
  : ObjectWriter(), m_Backend(pBackend), m_Config(pConfig)
{
}

ELFObjectWriter::~ELFObjectWriter()
{
}

void ELFObjectWriter::writeSection(Module& pModule,
                                   FileOutputBuffer& pOutput, LDSection *section)
{
  MemoryRegion region;
  // Request output region
  switch (section->kind()) {
  case LDFileFormat::Note:
    if (section->getSectionData() == NULL)
      return;
    // Fall through
  case LDFileFormat::TEXT:
  case LDFileFormat::DATA:
  case LDFileFormat::Relocation:
  case LDFileFormat::Target:
  case LDFileFormat::Debug:
  case LDFileFormat::GCCExceptTable:
  case LDFileFormat::EhFrame: {
    region = pOutput.request(section->offset(), section->size());
    if (region.size() == 0) {
      return;
    }
    break;
  }
  case LDFileFormat::Null:
  case LDFileFormat::NamePool:
  case LDFileFormat::BSS:
  case LDFileFormat::MetaData:
  case LDFileFormat::Version:
  case LDFileFormat::EhFrameHdr:
  case LDFileFormat::StackNote:
    // Ignore these sections
    return;
  default:
    llvm::errs() << "WARNING: unsupported section kind: "
                 << section->kind()
                 << " of section "
                 << section->name()
                 << ".\n";
    return;
  }

  // Write out sections with data
  switch(section->kind()) {
  case LDFileFormat::GCCExceptTable:
  case LDFileFormat::TEXT:
  case LDFileFormat::DATA:
  case LDFileFormat::Debug:
  case LDFileFormat::Note:
    emitSectionData(*section, region);
    break;
  case LDFileFormat::EhFrame:
    emitEhFrame(pModule, *section->getEhFrame(), region);
    break;
  case LDFileFormat::Relocation:
    // sort relocation for the benefit of the dynamic linker.
    target().sortRelocation(*section);

    emitRelocation(m_Config, *section, region);
    break;
  case LDFileFormat::Target:
    target().emitSectionData(*section, region);
    break;
  default:
    llvm_unreachable("invalid section kind");
  }
}

std::error_code ELFObjectWriter::writeObject(Module& pModule,
                                             FileOutputBuffer& pOutput)
{
  bool is_dynobj = m_Config.codeGenType() == LinkerConfig::DynObj;
  bool is_exec = m_Config.codeGenType() == LinkerConfig::Exec;
  bool is_binary = m_Config.codeGenType() == LinkerConfig::Binary;
  bool is_object = m_Config.codeGenType() == LinkerConfig::Object;

  assert(is_dynobj || is_exec || is_binary || is_object);

  if (is_dynobj || is_exec) {
    // Allow backend to sort symbols before emitting
    target().orderSymbolTable(pModule);

    // Write out the interpreter section: .interp
    target().emitInterp(pOutput);

    // Write out name pool sections: .dynsym, .dynstr, .hash
    target().emitDynNamePools(pModule, pOutput);
  }

  if (is_object || is_dynobj || is_exec) {
    // Write out name pool sections: .symtab, .strtab
    target().emitRegNamePools(pModule, pOutput);
  }

  if (is_binary) {
    // Iterate over the loadable segments and write the corresponding sections
    ELFSegmentFactory::iterator seg, segEnd = target().elfSegmentTable().end();

    for (seg = target().elfSegmentTable().begin(); seg != segEnd; ++seg) {
      if (llvm::ELF::PT_LOAD == (*seg)->type()) {
        ELFSegment::iterator sect, sectEnd = (*seg)->end();
        for (sect = (*seg)->begin(); sect != sectEnd; ++sect)
          writeSection(pModule, pOutput, *sect);
      }
    }
  } else {
    // Write out regular ELF sections
    Module::iterator sect, sectEnd = pModule.end();
    for (sect = pModule.begin(); sect != sectEnd; ++sect)
      writeSection(pModule, pOutput, *sect);

    emitShStrTab(target().getOutputFormat()->getShStrTab(), pModule, pOutput);

    if (m_Config.targets().is32Bits()) {
      // Write out ELF header
      // Write out section header table
      writeELFHeader<32>(m_Config, pModule, pOutput);
      if (is_dynobj || is_exec)
        emitProgramHeader<32>(pOutput);

      emitSectionHeader<32>(pModule, m_Config, pOutput);
    }
    else if (m_Config.targets().is64Bits()) {
      // Write out ELF header
      // Write out section header table
      writeELFHeader<64>(m_Config, pModule, pOutput);
      if (is_dynobj || is_exec)
        emitProgramHeader<64>(pOutput);

      emitSectionHeader<64>(pModule, m_Config, pOutput);
    }
    else
      return llvm::make_error_code(llvm::errc::function_not_supported);
  }

  return std::error_code();
}

// getOutputSize - count the final output size
size_t ELFObjectWriter::getOutputSize(const Module& pModule) const
{
  if (m_Config.targets().is32Bits()) {
    return getLastStartOffset<32>(pModule) +
           sizeof(ELFSizeTraits<32>::Shdr) * pModule.size();
  } else if (m_Config.targets().is64Bits()) {
    return getLastStartOffset<64>(pModule) +
           sizeof(ELFSizeTraits<64>::Shdr) * pModule.size();
  } else {
    assert(0 && "Invalid ELF Class");
    return 0;
  }
}

// writeELFHeader - emit ElfXX_Ehdr
template<size_t SIZE>
void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig,
                                     const Module& pModule,
                                     FileOutputBuffer& pOutput) const
{
  typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
  typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;
  typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;

  // ELF header must start from 0x0
  MemoryRegion region = pOutput.request(0, sizeof(ElfXX_Ehdr));
  ElfXX_Ehdr* header = (ElfXX_Ehdr*)region.begin();

  memcpy(header->e_ident, ElfMagic, EI_MAG3+1);

  header->e_ident[EI_CLASS]      = (SIZE == 32) ? ELFCLASS32 : ELFCLASS64;
  header->e_ident[EI_DATA]       = pConfig.targets().isLittleEndian()?
                                       ELFDATA2LSB : ELFDATA2MSB;
  header->e_ident[EI_VERSION]    = target().getInfo().ELFVersion();
  header->e_ident[EI_OSABI]      = target().getInfo().OSABI();
  header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion();

  // FIXME: add processor-specific and core file types.
  switch(pConfig.codeGenType()) {
    case LinkerConfig::Object:
      header->e_type = ET_REL;
      break;
    case LinkerConfig::DynObj:
      header->e_type = ET_DYN;
      break;
    case LinkerConfig::Exec:
      header->e_type = ET_EXEC;
      break;
    default:
      llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n";
      header->e_type = ET_NONE;
  }
  header->e_machine   = target().getInfo().machine();
  header->e_version   = header->e_ident[EI_VERSION];
  header->e_entry     = getEntryPoint(pConfig, pModule);

  if (LinkerConfig::Object != pConfig.codeGenType())
    header->e_phoff   = sizeof(ElfXX_Ehdr);
  else
    header->e_phoff   = 0x0;

  header->e_shoff     = getLastStartOffset<SIZE>(pModule);
  header->e_flags     = target().getInfo().flags();
  header->e_ehsize    = sizeof(ElfXX_Ehdr);
  header->e_phentsize = sizeof(ElfXX_Phdr);
  header->e_phnum     = target().elfSegmentTable().size();
  header->e_shentsize = sizeof(ElfXX_Shdr);
  header->e_shnum     = pModule.size();
  header->e_shstrndx  = pModule.getSection(".shstrtab")->index();
}

/// getEntryPoint
uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig,
                                        const Module& pModule) const
{
  llvm::StringRef entry_name = target().getEntry(pModule);
  uint64_t result = 0x0;

  bool issue_warning = (pModule.getScript().hasEntry() &&
                        LinkerConfig::Object != pConfig.codeGenType() &&
                        LinkerConfig::DynObj != pConfig.codeGenType());

  const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name);

  // found the symbol
  if (NULL != entry_symbol) {
    if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) {
      llvm::errs() << "WARNING: entry symbol '"
                   << entry_symbol->name()
                   << "' exists but is not defined.\n";
    }
    result = entry_symbol->value();
  }
  // not in the symbol pool
  else {
    // We should parse entry as a number.
    // @ref GNU ld manual, Options -e. e.g., -e 0x1000.
    char* endptr;
    result = strtoull(entry_name.data(), &endptr, 0);
    if (*endptr != '\0') {
      if (issue_warning) {
        llvm::errs() << "cannot find entry symbol '"
                     << entry_name.data()
                     << "'.\n";
      }
      result = 0x0;
    }
  }
  return result;
}

// emitSectionHeader - emit ElfXX_Shdr
template<size_t SIZE>
void ELFObjectWriter::emitSectionHeader(const Module& pModule,
                                        const LinkerConfig& pConfig,
                                        FileOutputBuffer& pOutput) const
{
  typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr;

  // emit section header
  unsigned int sectNum = pModule.size();
  unsigned int header_size = sizeof(ElfXX_Shdr) * sectNum;
  MemoryRegion region = pOutput.request(getLastStartOffset<SIZE>(pModule),
                                        header_size);
  ElfXX_Shdr* shdr = (ElfXX_Shdr*)region.begin();

  // Iterate the SectionTable in LDContext
  unsigned int sectIdx = 0;
  unsigned int shstridx = 0; // NULL section has empty name
  for (; sectIdx < sectNum; ++sectIdx) {
    const LDSection *ld_sect   = pModule.getSectionTable().at(sectIdx);
    shdr[sectIdx].sh_name      = shstridx;
    shdr[sectIdx].sh_type      = ld_sect->type();
    shdr[sectIdx].sh_flags     = ld_sect->flag();
    shdr[sectIdx].sh_addr      = ld_sect->addr();
    shdr[sectIdx].sh_offset    = ld_sect->offset();
    shdr[sectIdx].sh_size      = ld_sect->size();
    shdr[sectIdx].sh_addralign = ld_sect->align();
    shdr[sectIdx].sh_entsize   = getSectEntrySize<SIZE>(*ld_sect);
    shdr[sectIdx].sh_link      = getSectLink(*ld_sect, pConfig);
    shdr[sectIdx].sh_info      = getSectInfo(*ld_sect);

    // adjust strshidx
    shstridx += ld_sect->name().size() + 1;
  }
}

// emitProgramHeader - emit ElfXX_Phdr
template<size_t SIZE>
void ELFObjectWriter::emitProgramHeader(FileOutputBuffer& pOutput) const
{
  typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr;
  typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr;

  uint64_t start_offset, phdr_size;

  start_offset = sizeof(ElfXX_Ehdr);
  phdr_size = sizeof(ElfXX_Phdr);
  // Program header must start directly after ELF header
  MemoryRegion region = pOutput.request(start_offset,
      target().elfSegmentTable().size() * phdr_size);

  ElfXX_Phdr* phdr = (ElfXX_Phdr*)region.begin();

  // Iterate the elf segment table in GNULDBackend
  size_t index = 0;
  ELFSegmentFactory::const_iterator seg = target().elfSegmentTable().begin(),
                                 segEnd = target().elfSegmentTable().end();
  for (; seg != segEnd; ++seg, ++index) {
    phdr[index].p_type   = (*seg)->type();
    phdr[index].p_flags  = (*seg)->flag();
    phdr[index].p_offset = (*seg)->offset();
    phdr[index].p_vaddr  = (*seg)->vaddr();
    phdr[index].p_paddr  = (*seg)->paddr();
    phdr[index].p_filesz = (*seg)->filesz();
    phdr[index].p_memsz  = (*seg)->memsz();
    phdr[index].p_align  = (*seg)->align();
  }
}

/// emitShStrTab - emit section string table
void
ELFObjectWriter::emitShStrTab(const LDSection& pShStrTab,
                              const Module& pModule,
                              FileOutputBuffer& pOutput)
{
  // write out data
  MemoryRegion region = pOutput.request(pShStrTab.offset(), pShStrTab.size());
  char* data = (char*)region.begin();
  size_t shstrsize = 0;
  Module::const_iterator section, sectEnd = pModule.end();
  for (section = pModule.begin(); section != sectEnd; ++section) {
    strcpy((char*)(data + shstrsize), (*section)->name().data());
    shstrsize += (*section)->name().size() + 1;
  }
}

/// emitSectionData
void
ELFObjectWriter::emitSectionData(const LDSection& pSection,
                                 MemoryRegion& pRegion) const
{
  const SectionData* sd = NULL;
  switch (pSection.kind()) {
    case LDFileFormat::Relocation:
      assert(pSection.hasRelocData());
      return;
    case LDFileFormat::EhFrame:
      assert(pSection.hasEhFrame());
      sd = pSection.getEhFrame()->getSectionData();
      break;
    default:
      assert(pSection.hasSectionData());
      sd = pSection.getSectionData();
      break;
  }
  emitSectionData(*sd, pRegion);
}

/// emitEhFrame
void ELFObjectWriter::emitEhFrame(Module& pModule,
                                  EhFrame& pFrame, MemoryRegion& pRegion) const
{
  emitSectionData(*pFrame.getSectionData(), pRegion);

  // Patch FDE field (offset to CIE)
  for (EhFrame::cie_iterator i = pFrame.cie_begin(), e = pFrame.cie_end();
       i != e; ++i) {
    EhFrame::CIE& cie = **i;
    for (EhFrame::fde_iterator fi = cie.begin(), fe = cie.end();
         fi != fe; ++fi) {
      EhFrame::FDE& fde = **fi;
      if (fde.getRecordType() == EhFrame::RECORD_GENERATED) {
        // Patch PLT offset
        LDSection* plt_sect = pModule.getSection(".plt");
        assert (plt_sect && "We have no plt but have corresponding eh_frame?");
        uint64_t plt_offset = plt_sect->offset();
        // FDE entry for PLT is always 32-bit
        uint64_t fde_offset = pFrame.getSection().offset() + fde.getOffset() +
                              EhFrame::getDataStartOffset<32>();
        int32_t offset = fde_offset - plt_offset;
        if (plt_offset < fde_offset)
          offset = -offset;
        memcpy(pRegion.begin() + fde.getOffset() +
                                 EhFrame::getDataStartOffset<32>(),
                                 &offset, 4);
        uint32_t size = plt_sect->size();
        memcpy(pRegion.begin() + fde.getOffset() +
                                 EhFrame::getDataStartOffset<32>() + 4,
                                 &size, 4);
      }
      uint64_t fde_cie_ptr_offset = fde.getOffset() +
                                    EhFrame::getDataStartOffset<32>() -
                                    /*ID*/4;
      uint64_t cie_start_offset = cie.getOffset();
      int32_t offset = fde_cie_ptr_offset - cie_start_offset;
      if (fde_cie_ptr_offset < cie_start_offset)
        offset = -offset;
      memcpy(pRegion.begin() + fde_cie_ptr_offset, &offset, 4);
    } // for loop fde_iterator
  } // for loop cie_iterator
}

/// emitRelocation
void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig,
                                     const LDSection& pSection,
                                     MemoryRegion& pRegion) const
{
  const RelocData* sect_data = pSection.getRelocData();
  assert(NULL != sect_data && "SectionData is NULL in emitRelocation!");

  if (pSection.type() == SHT_REL) {
    if (pConfig.targets().is32Bits())
      emitRel<32>(pConfig, *sect_data, pRegion);
    else if (pConfig.targets().is64Bits())
      emitRel<64>(pConfig, *sect_data, pRegion);
    else {
      fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str()
                                        << pConfig.targets().bitclass();
    }
  } else if (pSection.type() == SHT_RELA) {
    if (pConfig.targets().is32Bits())
      emitRela<32>(pConfig, *sect_data, pRegion);
    else if (pConfig.targets().is64Bits())
      emitRela<64>(pConfig, *sect_data, pRegion);
    else {
      fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str()
                                        << pConfig.targets().bitclass();
    }
  } else
    llvm::report_fatal_error("unsupported relocation section type!");
}


// emitRel - emit ElfXX_Rel
template<size_t SIZE>
void ELFObjectWriter::emitRel(const LinkerConfig& pConfig,
                              const RelocData& pRelocData,
                              MemoryRegion& pRegion) const
{
  typedef typename ELFSizeTraits<SIZE>::Rel  ElfXX_Rel;
  typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
  typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;

  ElfXX_Rel* rel = reinterpret_cast<ElfXX_Rel*>(pRegion.begin());

  const Relocation* relocation = 0;
  const FragmentRef* frag_ref = 0;

  for (RelocData::const_iterator it = pRelocData.begin(),
       ie = pRelocData.end(); it != ie; ++it, ++rel) {
    ElfXX_Addr r_offset = 0;
    ElfXX_Word r_sym = 0;

    relocation = &(llvm::cast<Relocation>(*it));
    frag_ref = &(relocation->targetRef());

    if(LinkerConfig::DynObj == pConfig.codeGenType() ||
       LinkerConfig::Exec == pConfig.codeGenType()) {
      r_offset = static_cast<ElfXX_Addr>(
                      frag_ref->frag()->getParent()->getSection().addr() +
                      frag_ref->getOutputOffset());
    }
    else {
      r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
    }

    if( relocation->symInfo() == NULL )
      r_sym = 0;
    else
      r_sym = static_cast<ElfXX_Word>(
              target().getSymbolIdx(relocation->symInfo()->outSymbol()));

    target().emitRelocation(*rel, relocation->type(), r_sym, r_offset);
  }
}

// emitRela - emit ElfXX_Rela
template<size_t SIZE>
void ELFObjectWriter::emitRela(const LinkerConfig& pConfig,
                               const RelocData& pRelocData,
                               MemoryRegion& pRegion) const
{
  typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela;
  typedef typename ELFSizeTraits<SIZE>::Addr ElfXX_Addr;
  typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;

  ElfXX_Rela* rel = reinterpret_cast<ElfXX_Rela*>(pRegion.begin());

  const Relocation* relocation = 0;
  const FragmentRef* frag_ref = 0;

  for (RelocData::const_iterator it = pRelocData.begin(),
       ie = pRelocData.end(); it != ie; ++it, ++rel) {
    ElfXX_Addr r_offset = 0;
    ElfXX_Word r_sym = 0;

    relocation = &(llvm::cast<Relocation>(*it));
    frag_ref = &(relocation->targetRef());

    if(LinkerConfig::DynObj == pConfig.codeGenType() ||
       LinkerConfig::Exec == pConfig.codeGenType()) {
      r_offset = static_cast<ElfXX_Addr>(
                      frag_ref->frag()->getParent()->getSection().addr() +
                      frag_ref->getOutputOffset());
    }
    else {
      r_offset = static_cast<ElfXX_Addr>(frag_ref->getOutputOffset());
    }

    if( relocation->symInfo() == NULL )
      r_sym = 0;
    else
      r_sym = static_cast<ElfXX_Word>(
              target().getSymbolIdx(relocation->symInfo()->outSymbol()));

    target().emitRelocation(*rel, relocation->type(),
                            r_sym, r_offset, relocation->addend());
  }
}


/// getSectEntrySize - compute ElfXX_Shdr::sh_entsize
template<size_t SIZE>
uint64_t ELFObjectWriter::getSectEntrySize(const LDSection& pSection) const
{
  typedef typename ELFSizeTraits<SIZE>::Word ElfXX_Word;
  typedef typename ELFSizeTraits<SIZE>::Sym  ElfXX_Sym;
  typedef typename ELFSizeTraits<SIZE>::Rel  ElfXX_Rel;
  typedef typename ELFSizeTraits<SIZE>::Rela ElfXX_Rela;
  typedef typename ELFSizeTraits<SIZE>::Dyn  ElfXX_Dyn;

  if (llvm::ELF::SHT_DYNSYM == pSection.type() ||
      llvm::ELF::SHT_SYMTAB == pSection.type())
    return sizeof(ElfXX_Sym);
  if (llvm::ELF::SHT_REL == pSection.type())
    return sizeof(ElfXX_Rel);
  if (llvm::ELF::SHT_RELA == pSection.type())
    return sizeof(ElfXX_Rela);
  if (llvm::ELF::SHT_HASH     == pSection.type() ||
      llvm::ELF::SHT_GNU_HASH == pSection.type())
    return sizeof(ElfXX_Word);
  if (llvm::ELF::SHT_DYNAMIC == pSection.type())
    return sizeof(ElfXX_Dyn);
  // FIXME: We should get the entsize from input since the size of each
  // character is specified in the section header's sh_entsize field.
  // For example, traditional string is 0x1, UCS-2 is 0x2, ... and so on.
  // Ref: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html
  if (pSection.flag() & llvm::ELF::SHF_STRINGS)
    return 0x1;
  return 0x0;
}

/// getSectLink - compute ElfXX_Shdr::sh_link
uint64_t ELFObjectWriter::getSectLink(const LDSection& pSection,
                                      const LinkerConfig& pConfig) const
{
  if (llvm::ELF::SHT_SYMTAB == pSection.type())
    return target().getOutputFormat()->getStrTab().index();
  if (llvm::ELF::SHT_DYNSYM == pSection.type())
    return target().getOutputFormat()->getDynStrTab().index();
  if (llvm::ELF::SHT_DYNAMIC == pSection.type())
    return target().getOutputFormat()->getDynStrTab().index();
  if (llvm::ELF::SHT_HASH     == pSection.type() ||
      llvm::ELF::SHT_GNU_HASH == pSection.type())
    return target().getOutputFormat()->getDynSymTab().index();
  if (llvm::ELF::SHT_REL == pSection.type() ||
      llvm::ELF::SHT_RELA == pSection.type()) {
    if (LinkerConfig::Object == pConfig.codeGenType())
      return target().getOutputFormat()->getSymTab().index();
    else
      return target().getOutputFormat()->getDynSymTab().index();
  }
  // FIXME: currently we link ARM_EXIDX section to output text section here
  if (llvm::ELF::SHT_ARM_EXIDX == pSection.type())
    return target().getOutputFormat()->getText().index();
  return llvm::ELF::SHN_UNDEF;
}

/// getSectInfo - compute ElfXX_Shdr::sh_info
uint64_t ELFObjectWriter::getSectInfo(const LDSection& pSection) const
{
  if (llvm::ELF::SHT_SYMTAB == pSection.type() ||
      llvm::ELF::SHT_DYNSYM == pSection.type())
    return pSection.getInfo();

  if (llvm::ELF::SHT_REL == pSection.type() ||
      llvm::ELF::SHT_RELA == pSection.type()) {
    const LDSection* info_link = pSection.getLink();
    if (NULL != info_link)
      return info_link->index();
  }

  return 0x0;
}

/// getLastStartOffset
template<>
uint64_t ELFObjectWriter::getLastStartOffset<32>(const Module& pModule) const
{
  const LDSection* lastSect = pModule.back();
  assert(lastSect != NULL);
  return Align<32>(lastSect->offset() + lastSect->size());
}

/// getLastStartOffset
template<>
uint64_t ELFObjectWriter::getLastStartOffset<64>(const Module& pModule) const
{
  const LDSection* lastSect = pModule.back();
  assert(lastSect != NULL);
  return Align<64>(lastSect->offset() + lastSect->size());
}

/// emitSectionData
void ELFObjectWriter::emitSectionData(const SectionData& pSD,
                                      MemoryRegion& pRegion) const
{
  SectionData::const_iterator fragIter, fragEnd = pSD.end();
  size_t cur_offset = 0;
  for (fragIter = pSD.begin(); fragIter != fragEnd; ++fragIter) {
    size_t size = fragIter->size();
    switch(fragIter->getKind()) {
      case Fragment::Region: {
        const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter);
        const char* from = region_frag.getRegion().begin();
        memcpy(pRegion.begin() + cur_offset, from, size);
        break;
      }
      case Fragment::Alignment: {
        // TODO: emit values with different sizes (> 1 byte), and emit nops
        const AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter);
        uint64_t count = size / align_frag.getValueSize();
        switch (align_frag.getValueSize()) {
          case 1u:
            std::memset(pRegion.begin() + cur_offset,
                        align_frag.getValue(),
                        count);
            break;
          default:
            llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n");
            break;
        }
        break;
      }
      case Fragment::Fillment: {
        const FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter);
        if (0 == size ||
            0 == fill_frag.getValueSize() ||
            0 == fill_frag.size()) {
          // ignore virtual fillment
          break;
        }

        uint64_t num_tiles = fill_frag.size() / fill_frag.getValueSize();
        for (uint64_t i = 0; i != num_tiles; ++i) {
          std::memset(pRegion.begin() + cur_offset,
                      fill_frag.getValue(),
                      fill_frag.getValueSize());
        }
        break;
      }
      case Fragment::Stub: {
        const Stub& stub_frag = llvm::cast<Stub>(*fragIter);
        memcpy(pRegion.begin() + cur_offset, stub_frag.getContent(), size);
        break;
      }
      case Fragment::Null: {
        assert(0x0 == size);
        break;
      }
      case Fragment::Target:
        llvm::report_fatal_error("Target fragment should not be in a regular section.\n");
        break;
      default:
        llvm::report_fatal_error("invalid fragment should not be in a regular section.\n");
        break;
    }
    cur_offset += size;
  }
}