| //===- ELFDynObjWriter.cpp ------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include <mcld/LD/ELFDynObjWriter.h> |
| #include <mcld/LD/LDSymbol.h> |
| #include <mcld/Target/GNULDBackend.h> |
| #include <mcld/MC/MCLDInput.h> |
| #include <mcld/MC/MCLDOutput.h> |
| #include <mcld/MC/MCLDInfo.h> |
| #include <mcld/MC/MCLinker.h> |
| #include <llvm/Support/ELF.h> |
| #include <vector> |
| |
| using namespace llvm; |
| using namespace mcld; |
| |
| |
| //========================== |
| // ELFDynObjWriter |
| ELFDynObjWriter::ELFDynObjWriter(GNULDBackend& pBackend, MCLinker& pLinker) |
| : DynObjWriter(pBackend), |
| ELFWriter(pBackend), |
| m_Backend(pBackend), |
| m_Linker(pLinker) { |
| |
| } |
| |
| ELFDynObjWriter::~ELFDynObjWriter() |
| { |
| } |
| |
| llvm::error_code ELFDynObjWriter::writeDynObj(Output& pOutput) |
| { |
| // Write out name pool sections: .dynsym, .dynstr, .hash |
| target().emitDynNamePools(pOutput, |
| m_Linker.getOutputSymbols(), |
| m_Linker.getLayout(), |
| m_Linker.getLDInfo()); |
| |
| // Write out name pool sections: .symtab, .strtab |
| target().emitRegNamePools(pOutput, |
| m_Linker.getOutputSymbols(), |
| m_Linker.getLayout(), |
| m_Linker.getLDInfo()); |
| |
| // Write out regular ELF sections |
| unsigned int secIdx = 0; |
| unsigned int secEnd = pOutput.context()->numOfSections(); |
| for (secIdx = 0; secIdx < secEnd; ++secIdx) { |
| LDSection* sect = pOutput.context()->getSection(secIdx); |
| MemoryRegion* region = NULL; |
| // request output region |
| switch(sect->kind()) { |
| case LDFileFormat::Regular: |
| case LDFileFormat::Relocation: |
| case LDFileFormat::Target: |
| case LDFileFormat::Debug: |
| case LDFileFormat::GCCExceptTable: |
| case LDFileFormat::EhFrame: { |
| region = pOutput.memArea()->request(sect->offset(), sect->size()); |
| if (NULL == region) { |
| llvm::report_fatal_error(llvm::Twine("cannot get enough memory region for output section[") + |
| llvm::Twine(secIdx) + |
| llvm::Twine("] - `") + |
| sect->name() + |
| llvm::Twine("'.\n")); |
| } |
| break; |
| } |
| case LDFileFormat::Null: |
| case LDFileFormat::NamePool: |
| case LDFileFormat::BSS: |
| case LDFileFormat::Note: |
| case LDFileFormat::MetaData: |
| case LDFileFormat::Version: |
| case LDFileFormat::EhFrameHdr: |
| // ignore these sections |
| continue; |
| default: { |
| llvm::errs() << "WARNING: unsupported section kind: " |
| << sect->kind() |
| << " of section " |
| << sect->name() |
| << ".\n"; |
| continue; |
| } |
| } |
| |
| // write out sections with data |
| switch(sect->kind()) { |
| case LDFileFormat::Regular: |
| case LDFileFormat::Debug: |
| case LDFileFormat::GCCExceptTable: |
| case LDFileFormat::EhFrame: { |
| // FIXME: if optimization of exception handling sections is enabled, |
| // then we should emit these sections by the other way. |
| emitSectionData(m_Linker.getLayout(), *sect, *region); |
| break; |
| } |
| case LDFileFormat::Relocation: |
| emitRelocation(m_Linker.getLayout(), pOutput, *sect, *region); |
| break; |
| case LDFileFormat::Target: |
| target().emitSectionData(pOutput, |
| *sect, |
| m_Linker.getLDInfo(), |
| m_Linker.getLayout(), |
| *region); |
| break; |
| default: |
| continue; |
| } |
| |
| } // end of for loop |
| |
| if (32 == target().bitclass()) { |
| // Write out ELF header |
| // Write out section header table |
| emitELF32ShStrTab(pOutput, m_Linker); |
| |
| writeELF32Header(m_Linker.getLDInfo(), |
| m_Linker.getLayout(), |
| target(), |
| pOutput); |
| |
| emitELF32ProgramHeader(pOutput, target()); |
| |
| emitELF32SectionHeader(pOutput, m_Linker); |
| } |
| else if (64 == target().bitclass()) { |
| // Write out ELF header |
| // Write out section header table |
| emitELF64ShStrTab(pOutput, m_Linker); |
| |
| writeELF64Header(m_Linker.getLDInfo(), |
| m_Linker.getLayout(), |
| target(), |
| pOutput); |
| |
| emitELF64ProgramHeader(pOutput, target()); |
| |
| emitELF64SectionHeader(pOutput, m_Linker); |
| } |
| else |
| return make_error_code(errc::not_supported); |
| pOutput.memArea()->clear(); |
| return llvm::make_error_code(llvm::errc::success); |
| } |
| |