xref: /freebsd/contrib/llvm-project/lld/ELF/Arch/AMDGPU.cpp (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
1 //===- AMDGPU.cpp ---------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "InputFiles.h"
10 #include "Symbols.h"
11 #include "Target.h"
12 #include "lld/Common/ErrorHandler.h"
13 #include "llvm/Object/ELF.h"
14 #include "llvm/Support/Endian.h"
15 
16 using namespace llvm;
17 using namespace llvm::object;
18 using namespace llvm::support::endian;
19 using namespace llvm::ELF;
20 using namespace lld;
21 using namespace lld::elf;
22 
23 namespace {
24 class AMDGPU final : public TargetInfo {
25 public:
26   AMDGPU();
27   uint32_t calcEFlags() const override;
28   void relocate(uint8_t *loc, const Relocation &rel,
29                 uint64_t val) const override;
30   RelExpr getRelExpr(RelType type, const Symbol &s,
31                      const uint8_t *loc) const override;
32   RelType getDynRel(RelType type) const override;
33 };
34 } // namespace
35 
36 AMDGPU::AMDGPU() {
37   relativeRel = R_AMDGPU_RELATIVE64;
38   gotRel = R_AMDGPU_ABS64;
39   noneRel = R_AMDGPU_NONE;
40   symbolicRel = R_AMDGPU_ABS64;
41 }
42 
43 static uint32_t getEFlags(InputFile *file) {
44   return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader()->e_flags;
45 }
46 
47 uint32_t AMDGPU::calcEFlags() const {
48   assert(!objectFiles.empty());
49   uint32_t ret = getEFlags(objectFiles[0]);
50 
51   // Verify that all input files have the same e_flags.
52   for (InputFile *f : makeArrayRef(objectFiles).slice(1)) {
53     if (ret == getEFlags(f))
54       continue;
55     error("incompatible e_flags: " + toString(f));
56     return 0;
57   }
58   return ret;
59 }
60 
61 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
62   switch (rel.type) {
63   case R_AMDGPU_ABS32:
64   case R_AMDGPU_GOTPCREL:
65   case R_AMDGPU_GOTPCREL32_LO:
66   case R_AMDGPU_REL32:
67   case R_AMDGPU_REL32_LO:
68     write32le(loc, val);
69     break;
70   case R_AMDGPU_ABS64:
71   case R_AMDGPU_REL64:
72     write64le(loc, val);
73     break;
74   case R_AMDGPU_GOTPCREL32_HI:
75   case R_AMDGPU_REL32_HI:
76     write32le(loc, val >> 32);
77     break;
78   default:
79     llvm_unreachable("unknown relocation");
80   }
81 }
82 
83 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
84                            const uint8_t *loc) const {
85   switch (type) {
86   case R_AMDGPU_ABS32:
87   case R_AMDGPU_ABS64:
88     return R_ABS;
89   case R_AMDGPU_REL32:
90   case R_AMDGPU_REL32_LO:
91   case R_AMDGPU_REL32_HI:
92   case R_AMDGPU_REL64:
93     return R_PC;
94   case R_AMDGPU_GOTPCREL:
95   case R_AMDGPU_GOTPCREL32_LO:
96   case R_AMDGPU_GOTPCREL32_HI:
97     return R_GOT_PC;
98   default:
99     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
100           ") against symbol " + toString(s));
101     return R_NONE;
102   }
103 }
104 
105 RelType AMDGPU::getDynRel(RelType type) const {
106   if (type == R_AMDGPU_ABS64)
107     return type;
108   return R_AMDGPU_NONE;
109 }
110 
111 TargetInfo *elf::getAMDGPUTargetInfo() {
112   static AMDGPU target;
113   return &target;
114 }
115