| //===- ELFReaderTest.cpp --------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include <cstdio> |
| |
| #include <llvm/Support/ELF.h> |
| #include <mcld/IRBuilder.h> |
| #include <mcld/TargetOptions.h> |
| #include <mcld/LD/ELFReader.h> |
| #include <mcld/MC/MCLDInput.h> |
| #include <mcld/Support/Path.h> |
| #include <../lib/Target/X86/X86LDBackend.h> |
| #include <../lib/Target/X86/X86GNUInfo.h> |
| |
| #include "ELFReaderTest.h" |
| |
| using namespace mcld; |
| using namespace mcld::sys::fs; |
| using namespace mcldtest; |
| |
| // Constructor can do set-up work for all test here. |
| ELFReaderTest::ELFReaderTest() |
| : m_pInput(NULL) |
| { |
| m_pConfig = new LinkerConfig("x86_64-linux-gnueabi"); |
| m_pConfig->targets().setEndian( TargetOptions::Little ); |
| m_pConfig->targets().setBitClass( 64 ); |
| Relocation::SetUp( *m_pConfig ); |
| |
| m_pInfo = new X86_64GNUInfo( m_pConfig->targets().triple() ); |
| m_pLDBackend = new X86_64GNULDBackend( *m_pConfig, m_pInfo ); |
| m_pELFReader = new ELFReader<64, true>( *m_pLDBackend ); |
| m_pModule = new Module(); |
| m_pIRBuilder = new IRBuilder( *m_pModule, *m_pConfig); |
| m_pELFObjReader = new ELFObjectReader(*m_pLDBackend, |
| *m_pIRBuilder, |
| *m_pConfig); |
| } |
| |
| // Destructor can do clean-up work that doesn't throw exceptions here. |
| ELFReaderTest::~ELFReaderTest() |
| { |
| delete m_pConfig; |
| delete m_pLDBackend; |
| delete m_pELFReader; |
| delete m_pModule; |
| delete m_pIRBuilder; |
| delete m_pELFObjReader; |
| } |
| |
| // SetUp() will be called immediately before each test. |
| void ELFReaderTest::SetUp() |
| { |
| Path path(TOPDIR); |
| path.append("unittests/test_x86_64.o"); |
| |
| m_pInput = m_pIRBuilder->ReadInput("test_x86_64", path); |
| ASSERT_TRUE(NULL!=m_pInput); |
| |
| ASSERT_TRUE(m_pInput->hasMemArea()); |
| size_t hdr_size = m_pELFReader->getELFHeaderSize(); |
| MemoryRegion* region = m_pInput->memArea()->request(m_pInput->fileOffset(), |
| hdr_size); |
| uint8_t* ELF_hdr = region->start(); |
| bool shdr_result = m_pELFReader->readSectionHeaders(*m_pInput, ELF_hdr); |
| m_pInput->memArea()->release(region); |
| ASSERT_TRUE(shdr_result); |
| } |
| |
| // TearDown() will be called immediately after each test. |
| void ELFReaderTest::TearDown() |
| { |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Testcases |
| //===----------------------------------------------------------------------===// |
| TEST_F( ELFReaderTest, read_section_headers ) { |
| ASSERT_EQ(m_pInput->context()->numOfSections(), 13); |
| LDContext::const_sect_iterator iter = m_pInput->context()->sectBegin(); |
| ++iter; /// test section[1] |
| ASSERT_EQ(".text", (*iter)->name()); |
| ASSERT_EQ(llvm::ELF::SHT_PROGBITS, (*iter)->type()); |
| ASSERT_EQ(0x40, (*iter)->offset()); |
| ASSERT_EQ(0x15, (*iter)->size()); |
| ASSERT_TRUE(llvm::ELF::SHF_ALLOC & (*iter)->flag()); //AX |
| ASSERT_EQ(0x4, (*iter)->align()); |
| ASSERT_EQ(NULL, (*iter)->getLink()); |
| ASSERT_EQ(0, (*iter)->getInfo()); |
| } |
| |
| TEST_F( ELFReaderTest, read_symbol_and_rela ) |
| { |
| ASSERT_TRUE(m_pInput->hasMemArea()); |
| ASSERT_TRUE(m_pInput->hasContext()); |
| m_pInput->setType(Input::Object); |
| |
| // -- read symbols |
| LDSection* symtab_shdr = m_pInput->context()->getSection(".symtab"); |
| ASSERT_TRUE(NULL!=symtab_shdr); |
| |
| LDSection* strtab_shdr = symtab_shdr->getLink(); |
| ASSERT_TRUE(NULL!=strtab_shdr); |
| |
| MemoryRegion* symtab_region = m_pInput->memArea()->request( |
| m_pInput->fileOffset() + symtab_shdr->offset(), |
| symtab_shdr->size()); |
| |
| MemoryRegion* strtab_region = m_pInput->memArea()->request( |
| m_pInput->fileOffset() + strtab_shdr->offset(), |
| strtab_shdr->size()); |
| char* strtab = reinterpret_cast<char*>(strtab_region->start()); |
| bool result = m_pELFReader->readSymbols(*m_pInput, *m_pIRBuilder, |
| *symtab_region, strtab); |
| ASSERT_TRUE(result); |
| ASSERT_EQ("hello.c", std::string(m_pInput->context()->getSymbol(1)->name())); |
| ASSERT_EQ("puts", std::string(m_pInput->context()->getSymbol(10)->name())); |
| ASSERT_TRUE(NULL==m_pInput->context()->getSymbol(11)); |
| m_pInput->memArea()->release(symtab_region); |
| m_pInput->memArea()->release(strtab_region); |
| |
| // -- read relocations |
| MemoryArea* mem = m_pInput->memArea(); |
| LDContext::sect_iterator rs = m_pInput->context()->relocSectBegin(); |
| ASSERT_TRUE(rs!=m_pInput->context()->relocSectEnd()); |
| ASSERT_EQ(".rela.text", (*rs)->name()); |
| |
| uint64_t offset = m_pInput->fileOffset() + (*rs)->offset(); |
| uint64_t size = (*rs)->size(); |
| MemoryRegion* region = mem->request(offset, size); |
| IRBuilder::CreateRelocData(**rs); /// create relocation data for the header |
| |
| ASSERT_EQ(llvm::ELF::SHT_RELA, (*rs)->type()); |
| ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, *region)); |
| mem->release(region); |
| |
| const RelocData::RelocationListType &rRelocs = |
| (*rs)->getRelocData()->getRelocationList(); |
| RelocData::const_iterator rReloc = rRelocs.begin(); |
| ASSERT_EQ(2, rRelocs.size()); |
| ASSERT_TRUE(rRelocs.end()!=rReloc); |
| ++rReloc; /// test rRelocs[1] |
| ASSERT_EQ("puts", std::string(rReloc->symInfo()->name())); |
| ASSERT_EQ(llvm::ELF::R_X86_64_PC32, rReloc->type()); |
| ASSERT_EQ(0x0, rReloc->symValue()); |
| ASSERT_EQ(-0x4, rReloc->addend()); |
| } |
| |
| TEST_F( ELFReaderTest, read_regular_sections ) { |
| ASSERT_TRUE( m_pELFObjReader->readSections(*m_pInput) ); |
| } |
| |
| TEST_F( ELFReaderTest, is_my_format ) { |
| ASSERT_TRUE( m_pELFObjReader->isMyFormat(*m_pInput) ); |
| } |
| |
| |