1//===- ELFReaderTest.cpp --------------------------------------------------===// 2// 3// The MCLinker Project 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9#include "ELFReaderTest.h" 10 11#include "mcld/IRBuilder.h" 12#include "mcld/TargetOptions.h" 13#include "mcld/LD/ELFReader.h" 14#include "mcld/LD/LDContext.h" 15#include "mcld/MC/Input.h" 16#include "mcld/Support/Path.h" 17#include "mcld/Support/MemoryArea.h" 18#include <../lib/Target/X86/X86LDBackend.h> 19#include <../lib/Target/X86/X86GNUInfo.h> 20 21#include <llvm/ADT/StringRef.h> 22#include <llvm/Support/ELF.h> 23 24#include <cstdio> 25 26using namespace mcld; 27using namespace mcld::sys::fs; 28using namespace mcldtest; 29 30// Constructor can do set-up work for all test here. 31ELFReaderTest::ELFReaderTest() : m_pInput(NULL) { 32 m_pConfig = new LinkerConfig("x86_64-linux-gnueabi"); 33 m_pConfig->targets().setEndian(TargetOptions::Little); 34 m_pConfig->targets().setBitClass(64); 35 Relocation::SetUp(*m_pConfig); 36 37 m_pScript = new LinkerScript(); 38 m_pInfo = new X86_64GNUInfo(m_pConfig->targets().triple()); 39 m_pLDBackend = new X86_64GNULDBackend(*m_pConfig, m_pInfo); 40 m_pELFReader = new ELFReader<64, true>(*m_pLDBackend); 41 m_pModule = new Module(*m_pScript); 42 m_pIRBuilder = new IRBuilder(*m_pModule, *m_pConfig); 43 m_pELFObjReader = 44 new ELFObjectReader(*m_pLDBackend, *m_pIRBuilder, *m_pConfig); 45} 46 47// Destructor can do clean-up work that doesn't throw exceptions here. 48ELFReaderTest::~ELFReaderTest() { 49 delete m_pConfig; 50 delete m_pLDBackend; 51 delete m_pELFReader; 52 delete m_pScript; 53 delete m_pModule; 54 delete m_pIRBuilder; 55 delete m_pELFObjReader; 56} 57 58// SetUp() will be called immediately before each test. 59void ELFReaderTest::SetUp() { 60 Path path(TOPDIR); 61 path.append("unittests/test_x86_64.o"); 62 63 m_pInput = m_pIRBuilder->ReadInput("test_x86_64", path); 64 ASSERT_TRUE(NULL != m_pInput); 65 66 ASSERT_TRUE(m_pInput->hasMemArea()); 67 size_t hdr_size = m_pELFReader->getELFHeaderSize(); 68 llvm::StringRef region = 69 m_pInput->memArea()->request(m_pInput->fileOffset(), hdr_size); 70 const char* ELF_hdr = region.begin(); 71 bool shdr_result = m_pELFReader->readSectionHeaders(*m_pInput, ELF_hdr); 72 ASSERT_TRUE(shdr_result); 73} 74 75// TearDown() will be called immediately after each test. 76void ELFReaderTest::TearDown() { 77} 78 79//===----------------------------------------------------------------------===// 80// Testcases 81//===----------------------------------------------------------------------===// 82TEST_F(ELFReaderTest, read_section_headers) { 83 ASSERT_EQ(m_pInput->context()->numOfSections(), 13u); 84 LDContext::const_sect_iterator iter = m_pInput->context()->sectBegin(); 85 ++iter; /// test section[1] 86 ASSERT_EQ(".text", (*iter)->name()); 87 ASSERT_EQ(llvm::ELF::SHT_PROGBITS, (*iter)->type()); 88 ASSERT_EQ(0x40u, (*iter)->offset()); 89 ASSERT_EQ(0x15u, (*iter)->size()); 90 ASSERT_TRUE(llvm::ELF::SHF_ALLOC & (*iter)->flag()); // AX 91 ASSERT_EQ(0x4u, (*iter)->align()); 92 ASSERT_EQ(NULL, (*iter)->getLink()); 93 ASSERT_EQ(0u, (*iter)->getInfo()); 94} 95 96TEST_F(ELFReaderTest, read_symbol_and_rela) { 97 ASSERT_TRUE(m_pInput->hasMemArea()); 98 ASSERT_TRUE(m_pInput->hasContext()); 99 m_pInput->setType(Input::Object); 100 101 // -- read symbols 102 LDSection* symtab_shdr = m_pInput->context()->getSection(".symtab"); 103 ASSERT_TRUE(NULL != symtab_shdr); 104 105 LDSection* strtab_shdr = symtab_shdr->getLink(); 106 ASSERT_TRUE(NULL != strtab_shdr); 107 108 llvm::StringRef symtab_region = m_pInput->memArea()->request( 109 m_pInput->fileOffset() + symtab_shdr->offset(), symtab_shdr->size()); 110 111 llvm::StringRef strtab_region = m_pInput->memArea()->request( 112 m_pInput->fileOffset() + strtab_shdr->offset(), strtab_shdr->size()); 113 const char* strtab = strtab_region.begin(); 114 bool result = m_pELFReader->readSymbols( 115 *m_pInput, *m_pIRBuilder, symtab_region, strtab); 116 ASSERT_TRUE(result); 117 ASSERT_EQ("hello.c", std::string(m_pInput->context()->getSymbol(1)->name())); 118 ASSERT_EQ("puts", std::string(m_pInput->context()->getSymbol(10)->name())); 119 ASSERT_TRUE(NULL == m_pInput->context()->getSymbol(11)); 120 121 // -- read relocations 122 MemoryArea* mem = m_pInput->memArea(); 123 LDContext::sect_iterator rs = m_pInput->context()->relocSectBegin(); 124 ASSERT_TRUE(rs != m_pInput->context()->relocSectEnd()); 125 ASSERT_EQ(".rela.text", (*rs)->name()); 126 127 uint64_t offset = m_pInput->fileOffset() + (*rs)->offset(); 128 uint64_t size = (*rs)->size(); 129 llvm::StringRef region = mem->request(offset, size); 130 IRBuilder::CreateRelocData(**rs); /// create relocation data for the header 131 132 ASSERT_EQ(llvm::ELF::SHT_RELA, (*rs)->type()); 133 ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, region)); 134 135 const RelocData::RelocationListType& rRelocs = 136 (*rs)->getRelocData()->getRelocationList(); 137 RelocData::const_iterator rReloc = rRelocs.begin(); 138 ASSERT_EQ(2u, rRelocs.size()); 139 ASSERT_TRUE(rRelocs.end() != rReloc); 140 ++rReloc; /// test rRelocs[1] 141 ASSERT_EQ("puts", std::string(rReloc->symInfo()->name())); 142 ASSERT_EQ(llvm::ELF::R_X86_64_PC32, rReloc->type()); 143 ASSERT_EQ(0x0u, rReloc->symValue()); 144 ASSERT_EQ(static_cast<mcld::Relocation::Address>(-0x4), rReloc->addend()); 145} 146 147TEST_F(ELFReaderTest, read_regular_sections) { 148 ASSERT_TRUE(m_pELFObjReader->readSections(*m_pInput)); 149} 150 151TEST_F(ELFReaderTest, is_my_format) { 152 bool doContinue; 153 ASSERT_TRUE(m_pELFObjReader->isMyFormat(*m_pInput, doContinue)); 154} 155