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