1 //===- AMDGPU.cpp ---------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "InputFiles.h"
12 #include "lld/Common/ErrorHandler.h"
13 #include "llvm/BinaryFormat/ELF.h"
14 #include "llvm/Support/Endian.h"
17 using namespace llvm::object
;
18 using namespace llvm::support::endian
;
19 using namespace llvm::ELF
;
21 using namespace lld::elf
;
24 class AMDGPU final
: public TargetInfo
{
26 uint32_t calcEFlagsV3() const;
27 uint32_t calcEFlagsV4() const;
28 uint32_t calcEFlagsV6() const;
32 uint32_t calcEFlags() const override
;
33 void relocate(uint8_t *loc
, const Relocation
&rel
,
34 uint64_t val
) const override
;
35 RelExpr
getRelExpr(RelType type
, const Symbol
&s
,
36 const uint8_t *loc
) const override
;
37 RelType
getDynRel(RelType type
) const override
;
38 int64_t getImplicitAddend(const uint8_t *buf
, RelType type
) const override
;
42 AMDGPU::AMDGPU(Ctx
&ctx
) : TargetInfo(ctx
) {
43 relativeRel
= R_AMDGPU_RELATIVE64
;
44 gotRel
= R_AMDGPU_ABS64
;
45 symbolicRel
= R_AMDGPU_ABS64
;
48 static uint32_t getEFlags(InputFile
*file
) {
49 return cast
<ObjFile
<ELF64LE
>>(file
)->getObj().getHeader().e_flags
;
52 uint32_t AMDGPU::calcEFlagsV3() const {
53 uint32_t ret
= getEFlags(ctx
.objectFiles
[0]);
55 // Verify that all input files have the same e_flags.
56 for (InputFile
*f
: ArrayRef(ctx
.objectFiles
).slice(1)) {
57 if (ret
== getEFlags(f
))
59 ErrAlways(ctx
) << "incompatible e_flags: " << f
;
65 uint32_t AMDGPU::calcEFlagsV4() const {
66 uint32_t retMach
= getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_MACH
;
68 getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_FEATURE_XNACK_V4
;
70 getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4
;
72 // Verify that all input files have compatible e_flags (same mach, all
73 // features in the same category are either ANY, ANY and ON, or ANY and OFF).
74 for (InputFile
*f
: ArrayRef(ctx
.objectFiles
).slice(1)) {
75 if (retMach
!= (getEFlags(f
) & EF_AMDGPU_MACH
)) {
76 Err(ctx
) << "incompatible mach: " << f
;
80 if (retXnack
== EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4
||
81 (retXnack
!= EF_AMDGPU_FEATURE_XNACK_ANY_V4
&&
82 (getEFlags(f
) & EF_AMDGPU_FEATURE_XNACK_V4
)
83 != EF_AMDGPU_FEATURE_XNACK_ANY_V4
)) {
84 if (retXnack
!= (getEFlags(f
) & EF_AMDGPU_FEATURE_XNACK_V4
)) {
85 Err(ctx
) << "incompatible xnack: " << f
;
89 if (retXnack
== EF_AMDGPU_FEATURE_XNACK_ANY_V4
)
90 retXnack
= getEFlags(f
) & EF_AMDGPU_FEATURE_XNACK_V4
;
93 if (retSramEcc
== EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4
||
94 (retSramEcc
!= EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
&&
95 (getEFlags(f
) & EF_AMDGPU_FEATURE_SRAMECC_V4
) !=
96 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
)) {
97 if (retSramEcc
!= (getEFlags(f
) & EF_AMDGPU_FEATURE_SRAMECC_V4
)) {
98 Err(ctx
) << "incompatible sramecc: " << f
;
102 if (retSramEcc
== EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
)
103 retSramEcc
= getEFlags(f
) & EF_AMDGPU_FEATURE_SRAMECC_V4
;
107 return retMach
| retXnack
| retSramEcc
;
110 uint32_t AMDGPU::calcEFlagsV6() const {
111 uint32_t flags
= calcEFlagsV4();
113 uint32_t genericVersion
=
114 getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_GENERIC_VERSION
;
116 // Verify that all input files have compatible generic version.
117 for (InputFile
*f
: ArrayRef(ctx
.objectFiles
).slice(1)) {
118 if (genericVersion
!= (getEFlags(f
) & EF_AMDGPU_GENERIC_VERSION
)) {
119 ErrAlways(ctx
) << "incompatible generic version: " << f
;
124 flags
|= genericVersion
;
128 uint32_t AMDGPU::calcEFlags() const {
129 if (ctx
.objectFiles
.empty())
132 uint8_t abiVersion
= cast
<ObjFile
<ELF64LE
>>(ctx
.objectFiles
[0])
135 .e_ident
[EI_ABIVERSION
];
136 switch (abiVersion
) {
137 case ELFABIVERSION_AMDGPU_HSA_V2
:
138 case ELFABIVERSION_AMDGPU_HSA_V3
:
139 return calcEFlagsV3();
140 case ELFABIVERSION_AMDGPU_HSA_V4
:
141 case ELFABIVERSION_AMDGPU_HSA_V5
:
142 return calcEFlagsV4();
143 case ELFABIVERSION_AMDGPU_HSA_V6
:
144 return calcEFlagsV6();
146 Err(ctx
) << "unknown abi version: " << abiVersion
;
151 void AMDGPU::relocate(uint8_t *loc
, const Relocation
&rel
, uint64_t val
) const {
154 case R_AMDGPU_GOTPCREL
:
155 case R_AMDGPU_GOTPCREL32_LO
:
157 case R_AMDGPU_REL32_LO
:
164 case R_AMDGPU_GOTPCREL32_HI
:
165 case R_AMDGPU_REL32_HI
:
166 write32le(loc
, val
>> 32);
168 case R_AMDGPU_REL16
: {
169 int64_t simm
= (static_cast<int64_t>(val
) - 4) / 4;
170 checkInt(ctx
, loc
, simm
, 16, rel
);
171 write16le(loc
, simm
);
175 llvm_unreachable("unknown relocation");
179 RelExpr
AMDGPU::getRelExpr(RelType type
, const Symbol
&s
,
180 const uint8_t *loc
) const {
186 case R_AMDGPU_REL32_LO
:
187 case R_AMDGPU_REL32_HI
:
191 case R_AMDGPU_GOTPCREL
:
192 case R_AMDGPU_GOTPCREL32_LO
:
193 case R_AMDGPU_GOTPCREL32_HI
:
196 Err(ctx
) << getErrorLoc(ctx
, loc
) << "unknown relocation (" << type
.v
197 << ") against symbol " << &s
;
202 RelType
AMDGPU::getDynRel(RelType type
) const {
203 if (type
== R_AMDGPU_ABS64
)
205 return R_AMDGPU_NONE
;
208 int64_t AMDGPU::getImplicitAddend(const uint8_t *buf
, RelType type
) const {
213 case R_AMDGPU_RELATIVE64
:
214 return read64(ctx
, buf
);
216 InternalErr(ctx
, buf
) << "cannot read addend for relocation " << type
;
221 void elf::setAMDGPUTargetInfo(Ctx
&ctx
) { ctx
.target
.reset(new AMDGPU(ctx
)); }