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;
31 uint32_t calcEFlags() const override
;
32 void relocate(uint8_t *loc
, const Relocation
&rel
,
33 uint64_t val
) const override
;
34 RelExpr
getRelExpr(RelType type
, const Symbol
&s
,
35 const uint8_t *loc
) const override
;
36 RelType
getDynRel(RelType type
) const override
;
37 int64_t getImplicitAddend(const uint8_t *buf
, RelType type
) const override
;
42 relativeRel
= R_AMDGPU_RELATIVE64
;
43 gotRel
= R_AMDGPU_ABS64
;
44 symbolicRel
= R_AMDGPU_ABS64
;
47 static uint32_t getEFlags(InputFile
*file
) {
48 return cast
<ObjFile
<ELF64LE
>>(file
)->getObj().getHeader().e_flags
;
51 uint32_t AMDGPU::calcEFlagsV3() const {
52 uint32_t ret
= getEFlags(ctx
.objectFiles
[0]);
54 // Verify that all input files have the same e_flags.
55 for (InputFile
*f
: ArrayRef(ctx
.objectFiles
).slice(1)) {
56 if (ret
== getEFlags(f
))
58 error("incompatible e_flags: " + toString(f
));
64 uint32_t AMDGPU::calcEFlagsV4() const {
65 uint32_t retMach
= getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_MACH
;
67 getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_FEATURE_XNACK_V4
;
69 getEFlags(ctx
.objectFiles
[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4
;
71 // Verify that all input files have compatible e_flags (same mach, all
72 // features in the same category are either ANY, ANY and ON, or ANY and OFF).
73 for (InputFile
*f
: ArrayRef(ctx
.objectFiles
).slice(1)) {
74 if (retMach
!= (getEFlags(f
) & EF_AMDGPU_MACH
)) {
75 error("incompatible mach: " + toString(f
));
79 if (retXnack
== EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4
||
80 (retXnack
!= EF_AMDGPU_FEATURE_XNACK_ANY_V4
&&
81 (getEFlags(f
) & EF_AMDGPU_FEATURE_XNACK_V4
)
82 != EF_AMDGPU_FEATURE_XNACK_ANY_V4
)) {
83 if (retXnack
!= (getEFlags(f
) & EF_AMDGPU_FEATURE_XNACK_V4
)) {
84 error("incompatible xnack: " + toString(f
));
88 if (retXnack
== EF_AMDGPU_FEATURE_XNACK_ANY_V4
)
89 retXnack
= getEFlags(f
) & EF_AMDGPU_FEATURE_XNACK_V4
;
92 if (retSramEcc
== EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4
||
93 (retSramEcc
!= EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
&&
94 (getEFlags(f
) & EF_AMDGPU_FEATURE_SRAMECC_V4
) !=
95 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
)) {
96 if (retSramEcc
!= (getEFlags(f
) & EF_AMDGPU_FEATURE_SRAMECC_V4
)) {
97 error("incompatible sramecc: " + toString(f
));
101 if (retSramEcc
== EF_AMDGPU_FEATURE_SRAMECC_ANY_V4
)
102 retSramEcc
= getEFlags(f
) & EF_AMDGPU_FEATURE_SRAMECC_V4
;
106 return retMach
| retXnack
| retSramEcc
;
109 uint32_t AMDGPU::calcEFlags() const {
110 if (ctx
.objectFiles
.empty())
113 uint8_t abiVersion
= cast
<ObjFile
<ELF64LE
>>(ctx
.objectFiles
[0])
116 .e_ident
[EI_ABIVERSION
];
117 switch (abiVersion
) {
118 case ELFABIVERSION_AMDGPU_HSA_V2
:
119 case ELFABIVERSION_AMDGPU_HSA_V3
:
120 return calcEFlagsV3();
121 case ELFABIVERSION_AMDGPU_HSA_V4
:
122 case ELFABIVERSION_AMDGPU_HSA_V5
:
123 return calcEFlagsV4();
125 error("unknown abi version: " + Twine(abiVersion
));
130 void AMDGPU::relocate(uint8_t *loc
, const Relocation
&rel
, uint64_t val
) const {
133 case R_AMDGPU_GOTPCREL
:
134 case R_AMDGPU_GOTPCREL32_LO
:
136 case R_AMDGPU_REL32_LO
:
143 case R_AMDGPU_GOTPCREL32_HI
:
144 case R_AMDGPU_REL32_HI
:
145 write32le(loc
, val
>> 32);
147 case R_AMDGPU_REL16
: {
148 int64_t simm
= (static_cast<int64_t>(val
) - 4) / 4;
149 checkInt(loc
, simm
, 16, rel
);
150 write16le(loc
, simm
);
154 llvm_unreachable("unknown relocation");
158 RelExpr
AMDGPU::getRelExpr(RelType type
, const Symbol
&s
,
159 const uint8_t *loc
) const {
165 case R_AMDGPU_REL32_LO
:
166 case R_AMDGPU_REL32_HI
:
170 case R_AMDGPU_GOTPCREL
:
171 case R_AMDGPU_GOTPCREL32_LO
:
172 case R_AMDGPU_GOTPCREL32_HI
:
175 error(getErrorLocation(loc
) + "unknown relocation (" + Twine(type
) +
176 ") against symbol " + toString(s
));
181 RelType
AMDGPU::getDynRel(RelType type
) const {
182 if (type
== R_AMDGPU_ABS64
)
184 return R_AMDGPU_NONE
;
187 int64_t AMDGPU::getImplicitAddend(const uint8_t *buf
, RelType type
) const {
192 case R_AMDGPU_RELATIVE64
:
195 internalLinkerError(getErrorLocation(buf
),
196 "cannot read addend for relocation " + toString(type
));
201 TargetInfo
*elf::getAMDGPUTargetInfo() {
202 static AMDGPU target
;