xref: /llvm-project-15.0.7/lld/ELF/Arch/PPC.cpp (revision 2bc3449d)
1 //===- PPC.cpp ------------------------------------------------------------===//
2 //
3 //                             The LLVM Linker
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 "Error.h"
11 #include "Symbols.h"
12 #include "Target.h"
13 #include "llvm/Support/Endian.h"
14 
15 using namespace llvm;
16 using namespace llvm::support::endian;
17 using namespace llvm::ELF;
18 using namespace lld;
19 using namespace lld::elf;
20 
21 namespace {
22 class PPC final : public TargetInfo {
23 public:
24   PPC() { GotBaseSymOff = 0x8000; }
25   void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
26   RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
27                      const uint8_t *Loc) const override;
28 };
29 } // namespace
30 
31 void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
32   switch (Type) {
33   case R_PPC_ADDR16_HA:
34     write16be(Loc, (Val + 0x8000) >> 16);
35     break;
36   case R_PPC_ADDR16_LO:
37     write16be(Loc, Val);
38     break;
39   case R_PPC_ADDR32:
40   case R_PPC_REL32:
41     write32be(Loc, Val);
42     break;
43   case R_PPC_REL24:
44     write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
45     break;
46   default:
47     error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
48   }
49 }
50 
51 RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S,
52                         const uint8_t *Loc) const {
53   switch (Type) {
54   case R_PPC_REL24:
55   case R_PPC_REL32:
56     return R_PC;
57   default:
58     return R_ABS;
59   }
60 }
61 
62 TargetInfo *elf::getPPCTargetInfo() {
63   static PPC Target;
64   return &Target;
65 }
66