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