1//===- AArch64CA53ErratumStub.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
10#include "AArch64CA53ErratumStub.h"
11#include "AArch64InsnHelpers.h"
12#include "AArch64LDBackend.h"
13#include "AArch64RelocationHelpers.h"
14#include "AArch64Relocator.h"
15
16#include "mcld/Fragment/FragmentRef.h"
17#include "mcld/Fragment/Relocation.h"
18#include "mcld/IRBuilder.h"
19#include "mcld/LD/BranchIsland.h"
20#include "mcld/LD/LDSymbol.h"
21#include "mcld/LD/ResolveInfo.h"
22
23#include <llvm/ADT/StringExtras.h>
24#include <llvm/Support/ELF.h>
25
26#include <cassert>
27
28namespace mcld {
29
30//===----------------------------------------------------------------------===//
31// AArch64CA53ErratumStub
32//===----------------------------------------------------------------------===//
33const uint32_t AArch64CA53ErratumStub::TEMPLATE[] = {
34  0x00000000,  // Placeholder for erratum insn
35  0x00000000,  // Palceholder for branch instruction
36};
37
38AArch64CA53ErratumStub::AArch64CA53ErratumStub()
39    : m_pData(NULL),
40      m_Name("erratum__prototype"),
41      m_Size(0x0) {
42  m_pData = TEMPLATE;
43  m_Size = sizeof(TEMPLATE);
44  addFixup(0x0, 0, AArch64Relocator::R_AARCH64_REWRITE_INSN);
45  addFixup(0x4, 0, llvm::ELF::R_AARCH64_JUMP26);
46}
47
48/// for doClone
49AArch64CA53ErratumStub::AArch64CA53ErratumStub(const uint32_t* pData,
50                                               size_t pSize,
51                                               const char* pName,
52                                               const_fixup_iterator pBegin,
53                                               const_fixup_iterator pEnd)
54    : m_pData(pData),
55      m_Name(pName),
56      m_Size(pSize) {
57  for (const_fixup_iterator it = pBegin, ie = pEnd; it != ie; ++it) {
58    addFixup(**it);
59  }
60}
61
62AArch64CA53ErratumStub::~AArch64CA53ErratumStub() {
63}
64
65bool AArch64CA53ErratumStub::isMyDuty(const FragmentRef& pFragRef) const {
66  return false;
67}
68
69void AArch64CA53ErratumStub::applyFixup(FragmentRef& pSrcFragRef,
70                                        IRBuilder& pBuilder,
71                                        BranchIsland& pIsland) {
72  assert(isMyDuty(pSrcFragRef));
73
74  // Build stub symbol name.
75  std::string sym_name("__");
76  sym_name.append(name())
77          .append(llvm::utohexstr(pIsland.numOfStubs()))
78          .append("@")
79          .append(pIsland.name());
80
81  // Create LDSymbol for the stub.
82  LDSymbol* stub_sym =
83      pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
84          sym_name,
85          ResolveInfo::NoType,
86          ResolveInfo::Define,
87          ResolveInfo::Local,
88          size(),
89          initSymValue(),
90          FragmentRef::Create(*this, initSymValue()),
91          ResolveInfo::Default);
92  setSymInfo(stub_sym->resolveInfo());
93
94  // Create the target symbol of the stub to the next instruction of erratum
95  // pattarn.
96  FragmentRef* target = FragmentRef::Create(*pSrcFragRef.frag(),
97                                            pSrcFragRef.offset() +
98                                                getErratumInsnOffset() +
99                                                AArch64InsnHelpers::InsnSize);
100  ResolveInfo* target_info = pBuilder.CreateLocalSymbol(*target);
101
102  // Apply the fixups.
103  fixup_iterator it = fixup_begin();
104  // Rewrite the first instruction as the erratum instruction.
105  Relocation* reloc =
106      Relocation::Create((*it)->type(),
107                         *(FragmentRef::Create(*this, (*it)->offset())),
108                         (*it)->addend());
109  reloc->setSymInfo(target_info);
110
111  std::unique_ptr<unsigned[]> code(new unsigned[getErratumSequenceSize() / 4]);
112  pSrcFragRef.memcpy(code.get(), getErratumSequenceSize(), 0);
113  reloc->target() =
114      code[getErratumInsnOffset() / AArch64InsnHelpers::InsnSize];
115  pIsland.addRelocation(*reloc);
116
117  // Construct the second instruction as a branch to target.
118  ++it;
119  reloc = Relocation::Create((*it)->type(),
120                             *(FragmentRef::Create(*this, (*it)->offset())),
121                             (*it)->addend());
122  reloc->setSymInfo(target_info);
123  reloc->target() = AArch64InsnHelpers::buildBranchInsn();
124  pIsland.addRelocation(*reloc);
125
126  assert((++it) == fixup_end());
127}
128
129const std::string& AArch64CA53ErratumStub::name() const {
130  return m_Name;
131}
132
133const uint32_t* AArch64CA53ErratumStub::getData() const {
134  return m_pData;
135}
136
137const uint8_t* AArch64CA53ErratumStub::getContent() const {
138  return reinterpret_cast<const uint8_t*>(m_pData);
139}
140
141size_t AArch64CA53ErratumStub::size() const {
142  return m_Size;
143}
144
145size_t AArch64CA53ErratumStub::alignment() const {
146  return 8;
147}
148
149}  // namespace mcld
150