summaryrefslogtreecommitdiff
path: root/lib/LD/BranchIsland.cpp
blob: 0405263dc5847bed437281cb919f839bb6535c68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//===- BranchIsland.cpp ---------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/LD/BranchIsland.h"

#include "mcld/Fragment/AlignFragment.h"
#include "mcld/Fragment/Stub.h"
#include "mcld/LD/LDSection.h"
#include "mcld/LD/ResolveInfo.h"

#include <sstream>

namespace mcld {

//==========================
// BranchIsland

BranchIsland::BranchIsland(Fragment& pEntryFrag, size_t pMaxSize, size_t pIndex)
    : m_Entry(pEntryFrag),
      m_pExit(pEntryFrag.getNextNode()),
      m_pRear(NULL),
      m_MaxSize(pMaxSize),
      m_Name("island-") {
  // island name
  std::ostringstream index;
  index << pIndex;
  m_Name.append(index.str());
}

BranchIsland::~BranchIsland() {
}

/// fragment iterators of the island
SectionData::iterator BranchIsland::begin() {
  return ++iterator(&m_Entry);
}

SectionData::const_iterator BranchIsland::begin() const {
  return ++iterator(&m_Entry);
}

SectionData::iterator BranchIsland::end() {
  if (m_pExit != NULL)
    return iterator(m_pExit);
  return m_Entry.getParent()->end();
}

SectionData::const_iterator BranchIsland::end() const {
  if (m_pExit != NULL)
    return iterator(m_pExit);
  return m_Entry.getParent()->end();
}

uint64_t BranchIsland::offset() const {
  return m_Entry.getOffset() + m_Entry.size();
}

size_t BranchIsland::size() const {
  size_t size = 0x0;
  if (numOfStubs() != 0x0) {
    size = m_pRear->getOffset() + m_pRear->size() -
           m_Entry.getNextNode()->getOffset();
  }
  return size;
}

size_t BranchIsland::maxSize() const {
  return m_MaxSize;
}

const std::string& BranchIsland::name() const {
  return m_Name;
}

size_t BranchIsland::numOfStubs() const {
  return m_StubMap.numOfEntries();
}

/// findStub - return true if there is a stub built from the given prototype
///            for the given relocation
Stub* BranchIsland::findStub(const Stub* pPrototype, const Relocation& pReloc) {
  Key key(pPrototype, pReloc.symInfo()->outSymbol(), pReloc.addend());
  StubMapType::iterator it = m_StubMap.find(key);
  if (it != m_StubMap.end()) {
    assert(it.getEntry()->value() != NULL);
    return it.getEntry()->value();
  }
  return NULL;
}

/// addStub - add a stub into the island
bool BranchIsland::addStub(const Stub* pPrototype,
                           const Relocation& pReloc,
                           Stub& pStub) {
  bool exist = false;
  Key key(pPrototype, pReloc.symInfo()->outSymbol(), pReloc.addend());
  StubEntryType* entry = m_StubMap.insert(key, exist);
  if (!exist) {
    entry->setValue(&pStub);
    m_pRear = &pStub;
    SectionData* sd = m_Entry.getParent();

    // insert alignment fragment
    // TODO: check if we can reduce this alignment fragment for some cases
    AlignFragment* align_frag =
        new AlignFragment(pStub.alignment(), 0x0, 1u, pStub.alignment() - 1);
    align_frag->setParent(sd);
    sd->getFragmentList().insert(end(), align_frag);
    align_frag->setOffset(align_frag->getPrevNode()->getOffset() +
                          align_frag->getPrevNode()->size());

    // insert stub fragment
    pStub.setParent(sd);
    sd->getFragmentList().insert(end(), &pStub);
    pStub.setOffset(pStub.getPrevNode()->getOffset() +
                    pStub.getPrevNode()->size());
  }
  return !exist;
}

/// addRelocation - add a relocation into island
bool BranchIsland::addRelocation(Relocation& pReloc) {
  m_Relocations.push_back(&pReloc);
  return true;
}

}  // namespace mcld