16f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===- ELFReaderTest.cpp --------------------------------------------------===//
26f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//
36f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//                     The MCLinker Project
46f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//
56f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// This file is distributed under the University of Illinois Open Source
66f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// License. See LICENSE.TXT for details.
76f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//
86f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===//
937b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "ELFReaderTest.h"
106f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
1137b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/IRBuilder.h"
1237b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/TargetOptions.h"
1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/ELFReader.h"
1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/LDContext.h"
1537b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/MC/Input.h"
1637b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/Path.h"
1737b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/MemoryArea.h"
186f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines#include <../lib/Target/X86/X86LDBackend.h>
196f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines#include <../lib/Target/X86/X86GNUInfo.h>
206f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
2137b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <llvm/ADT/StringRef.h>
2237b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <llvm/Support/ELF.h>
2337b74a387bb3993387029859c2d9d051c41c724eStephen Hines
2437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <cstdio>
256f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
266f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hinesusing namespace mcld;
276f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hinesusing namespace mcld::sys::fs;
286f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hinesusing namespace mcldtest;
296f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
306f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// Constructor can do set-up work for all test here.
3137b74a387bb3993387029859c2d9d051c41c724eStephen HinesELFReaderTest::ELFReaderTest() : m_pInput(NULL) {
326f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  m_pConfig = new LinkerConfig("x86_64-linux-gnueabi");
3337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pConfig->targets().setEndian(TargetOptions::Little);
3437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pConfig->targets().setBitClass(64);
3537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  Relocation::SetUp(*m_pConfig);
366f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
37f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  m_pScript = new LinkerScript();
3837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pInfo = new X86_64GNUInfo(m_pConfig->targets().triple());
3937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pLDBackend = new X86_64GNULDBackend(*m_pConfig, m_pInfo);
4037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pELFReader = new ELFReader<64, true>(*m_pLDBackend);
41f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  m_pModule = new Module(*m_pScript);
4237b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pIRBuilder = new IRBuilder(*m_pModule, *m_pConfig);
4337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  m_pELFObjReader =
4437b74a387bb3993387029859c2d9d051c41c724eStephen Hines      new ELFObjectReader(*m_pLDBackend, *m_pIRBuilder, *m_pConfig);
456f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
466f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
476f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// Destructor can do clean-up work that doesn't throw exceptions here.
4837b74a387bb3993387029859c2d9d051c41c724eStephen HinesELFReaderTest::~ELFReaderTest() {
496f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  delete m_pConfig;
506f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  delete m_pLDBackend;
516f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  delete m_pELFReader;
52f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  delete m_pScript;
536f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  delete m_pModule;
546f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  delete m_pIRBuilder;
556f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  delete m_pELFObjReader;
566f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
576f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
586f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// SetUp() will be called immediately before each test.
5937b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid ELFReaderTest::SetUp() {
606f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  Path path(TOPDIR);
616f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  path.append("unittests/test_x86_64.o");
626f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
636f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  m_pInput = m_pIRBuilder->ReadInput("test_x86_64", path);
6437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(NULL != m_pInput);
656f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
666f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_TRUE(m_pInput->hasMemArea());
676f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  size_t hdr_size = m_pELFReader->getELFHeaderSize();
6837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  llvm::StringRef region =
6937b74a387bb3993387029859c2d9d051c41c724eStephen Hines      m_pInput->memArea()->request(m_pInput->fileOffset(), hdr_size);
70f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  const char* ELF_hdr = region.begin();
716f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  bool shdr_result = m_pELFReader->readSectionHeaders(*m_pInput, ELF_hdr);
726f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_TRUE(shdr_result);
736f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
746f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
756f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// TearDown() will be called immediately after each test.
7637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid ELFReaderTest::TearDown() {
776f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
786f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
796f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===//
806f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines// Testcases
816f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines//===----------------------------------------------------------------------===//
8237b74a387bb3993387029859c2d9d051c41c724eStephen HinesTEST_F(ELFReaderTest, read_section_headers) {
83a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(m_pInput->context()->numOfSections(), 13u);
846f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  LDContext::const_sect_iterator iter = m_pInput->context()->sectBegin();
8537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ++iter;  /// test section[1]
866f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ(".text", (*iter)->name());
876f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ(llvm::ELF::SHT_PROGBITS, (*iter)->type());
88a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(0x40u, (*iter)->offset());
89a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(0x15u, (*iter)->size());
9037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(llvm::ELF::SHF_ALLOC & (*iter)->flag());  // AX
91a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(0x4u, (*iter)->align());
926f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ(NULL, (*iter)->getLink());
93a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(0u, (*iter)->getInfo());
946f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
956f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
9637b74a387bb3993387029859c2d9d051c41c724eStephen HinesTEST_F(ELFReaderTest, read_symbol_and_rela) {
976f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_TRUE(m_pInput->hasMemArea());
986f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_TRUE(m_pInput->hasContext());
996f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  m_pInput->setType(Input::Object);
1006f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
1016f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  // -- read symbols
1026f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  LDSection* symtab_shdr = m_pInput->context()->getSection(".symtab");
10337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(NULL != symtab_shdr);
1046f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
1056f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  LDSection* strtab_shdr = symtab_shdr->getLink();
10637b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(NULL != strtab_shdr);
1076f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
108f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  llvm::StringRef symtab_region = m_pInput->memArea()->request(
109f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines      m_pInput->fileOffset() + symtab_shdr->offset(), symtab_shdr->size());
1106f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
111f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  llvm::StringRef strtab_region = m_pInput->memArea()->request(
112f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines      m_pInput->fileOffset() + strtab_shdr->offset(), strtab_shdr->size());
113f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  const char* strtab = strtab_region.begin();
11437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  bool result = m_pELFReader->readSymbols(
11537b74a387bb3993387029859c2d9d051c41c724eStephen Hines      *m_pInput, *m_pIRBuilder, symtab_region, strtab);
1166f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_TRUE(result);
1176f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ("hello.c", std::string(m_pInput->context()->getSymbol(1)->name()));
1186f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ("puts", std::string(m_pInput->context()->getSymbol(10)->name()));
11937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(NULL == m_pInput->context()->getSymbol(11));
1206f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
1216f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  // -- read relocations
1226f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  MemoryArea* mem = m_pInput->memArea();
1236f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  LDContext::sect_iterator rs = m_pInput->context()->relocSectBegin();
12437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(rs != m_pInput->context()->relocSectEnd());
1256f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ(".rela.text", (*rs)->name());
1266f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
1276f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  uint64_t offset = m_pInput->fileOffset() + (*rs)->offset();
1286f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  uint64_t size = (*rs)->size();
129f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  llvm::StringRef region = mem->request(offset, size);
13037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  IRBuilder::CreateRelocData(**rs);  /// create relocation data for the header
1316f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
1326f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ(llvm::ELF::SHT_RELA, (*rs)->type());
133f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  ASSERT_TRUE(m_pELFReader->readRela(*m_pInput, **rs, region));
1346f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
13537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  const RelocData::RelocationListType& rRelocs =
13637b74a387bb3993387029859c2d9d051c41c724eStephen Hines      (*rs)->getRelocData()->getRelocationList();
1376f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  RelocData::const_iterator rReloc = rRelocs.begin();
138a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(2u, rRelocs.size());
13937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(rRelocs.end() != rReloc);
14037b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ++rReloc;  /// test rRelocs[1]
1416f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ("puts", std::string(rReloc->symInfo()->name()));
1426f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines  ASSERT_EQ(llvm::ELF::R_X86_64_PC32, rReloc->type());
143a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(0x0u, rReloc->symValue());
144a6c24dff8b7fa2551a3a885e77a2e814f5b764a2Stephen Hines  ASSERT_EQ(static_cast<mcld::Relocation::Address>(-0x4), rReloc->addend());
1456f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
1466f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
14737b74a387bb3993387029859c2d9d051c41c724eStephen HinesTEST_F(ELFReaderTest, read_regular_sections) {
14837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(m_pELFObjReader->readSections(*m_pInput));
1496f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
1506f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines
15137b74a387bb3993387029859c2d9d051c41c724eStephen HinesTEST_F(ELFReaderTest, is_my_format) {
152f33f6de54db174aa679a4b6d1e040d37e95541c0Stephen Hines  bool doContinue;
15337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  ASSERT_TRUE(m_pELFObjReader->isMyFormat(*m_pInput, doContinue));
1546f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines}
155