xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===-- SystemZELFObjectWriter.cpp - SystemZ ELF writer -------------------===//
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 "MCTargetDesc/SystemZMCAsmInfo.h"
10 #include "MCTargetDesc/SystemZMCFixups.h"
11 #include "MCTargetDesc/SystemZMCTargetDesc.h"
12 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCELFObjectWriter.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/MC/MCFixup.h"
17 #include "llvm/MC/MCObjectWriter.h"
18 #include "llvm/MC/MCValue.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include <cassert>
21 #include <cstdint>
22 #include <memory>
23 
24 using namespace llvm;
25 
26 namespace {
27 
28 class SystemZELFObjectWriter : public MCELFObjectTargetWriter {
29 public:
30   SystemZELFObjectWriter(uint8_t OSABI);
31   ~SystemZELFObjectWriter() override = default;
32 
33 protected:
34   // Override MCELFObjectTargetWriter.
35   unsigned getRelocType(const MCFixup &, const MCValue &,
36                         bool IsPCRel) const override;
37   bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override;
38   unsigned getAbsoluteReloc(SMLoc Loc, unsigned Kind) const;
39   unsigned getPCRelReloc(SMLoc Loc, unsigned Kind) const;
40 };
41 
42 } // end anonymous namespace
43 
44 SystemZELFObjectWriter::SystemZELFObjectWriter(uint8_t OSABI)
45     : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390,
46                               /*HasRelocationAddend_=*/true) {}
47 
48 // Return the relocation type for an absolute value of MCFixupKind Kind.
49 unsigned SystemZELFObjectWriter::getAbsoluteReloc(SMLoc Loc,
50                                                   unsigned Kind) const {
51   switch (Kind) {
52   case FK_Data_1:
53   case SystemZ::FK_390_U8Imm:
54   case SystemZ::FK_390_S8Imm:
55     return ELF::R_390_8;
56   case SystemZ::FK_390_U12Imm:
57     return ELF::R_390_12;
58   case FK_Data_2:
59   case SystemZ::FK_390_U16Imm:
60   case SystemZ::FK_390_S16Imm:
61     return ELF::R_390_16;
62   case SystemZ::FK_390_S20Imm:
63     return ELF::R_390_20;
64   case FK_Data_4:
65   case SystemZ::FK_390_U32Imm:
66   case SystemZ::FK_390_S32Imm:
67     return ELF::R_390_32;
68   case FK_Data_8:
69     return ELF::R_390_64;
70   }
71   reportError(Loc, "Unsupported absolute address");
72   return 0;
73 }
74 
75 // Return the relocation type for a PC-relative value of MCFixupKind Kind.
76 unsigned SystemZELFObjectWriter::getPCRelReloc(SMLoc Loc, unsigned Kind) const {
77   switch (Kind) {
78   case FK_Data_2:
79   case SystemZ::FK_390_U16Imm:
80   case SystemZ::FK_390_S16Imm:
81     return ELF::R_390_PC16;
82   case FK_Data_4:
83   case SystemZ::FK_390_U32Imm:
84   case SystemZ::FK_390_S32Imm:
85     return ELF::R_390_PC32;
86   case FK_Data_8:
87     return ELF::R_390_PC64;
88   case SystemZ::FK_390_PC12DBL:
89     return ELF::R_390_PC12DBL;
90   case SystemZ::FK_390_PC16DBL:
91     return ELF::R_390_PC16DBL;
92   case SystemZ::FK_390_PC24DBL:
93     return ELF::R_390_PC24DBL;
94   case SystemZ::FK_390_PC32DBL:
95     return ELF::R_390_PC32DBL;
96   }
97   reportError(Loc, "Unsupported PC-relative address");
98   return 0;
99 }
100 
101 unsigned SystemZELFObjectWriter::getRelocType(const MCFixup &Fixup,
102                                               const MCValue &Target,
103                                               bool IsPCRel) const {
104   SMLoc Loc = Fixup.getLoc();
105   unsigned Kind = Fixup.getKind();
106   auto Specifier = SystemZ::Specifier(Target.getSpecifier());
107   switch (Specifier) {
108   case SystemZ::S_INDNTPOFF:
109   case SystemZ::S_NTPOFF:
110   case SystemZ::S_TLSGD:
111   case SystemZ::S_TLSLD:
112   case SystemZ::S_TLSLDM:
113   case SystemZ::S_DTPOFF:
114     if (auto *SA = Target.getAddSym())
115       cast<MCSymbolELF>(SA)->setType(ELF::STT_TLS);
116     break;
117   default:
118     break;
119   }
120 
121   switch (Specifier) {
122   case SystemZ::S_None:
123     if (IsPCRel)
124       return getPCRelReloc(Loc, Kind);
125     return getAbsoluteReloc(Loc, Kind);
126 
127   case SystemZ::S_NTPOFF:
128     assert(!IsPCRel && "NTPOFF shouldn't be PC-relative");
129     switch (Kind) {
130     case FK_Data_4:
131       return ELF::R_390_TLS_LE32;
132     case FK_Data_8:
133       return ELF::R_390_TLS_LE64;
134     }
135     reportError(Loc, "Unsupported thread-local address (local-exec)");
136     return 0;
137 
138   case SystemZ::S_INDNTPOFF:
139     if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
140       return ELF::R_390_TLS_IEENT;
141     reportError(Loc,
142                 "Only PC-relative INDNTPOFF accesses are supported for now");
143     return 0;
144 
145   case SystemZ::S_DTPOFF:
146     assert(!IsPCRel && "DTPOFF shouldn't be PC-relative");
147     switch (Kind) {
148     case FK_Data_4:
149       return ELF::R_390_TLS_LDO32;
150     case FK_Data_8:
151       return ELF::R_390_TLS_LDO64;
152     }
153     reportError(Loc, "Unsupported thread-local address (local-dynamic)");
154     return 0;
155 
156   case SystemZ::S_TLSLDM:
157     assert(!IsPCRel && "TLSLDM shouldn't be PC-relative");
158     switch (Kind) {
159     case FK_Data_4:
160       return ELF::R_390_TLS_LDM32;
161     case FK_Data_8:
162       return ELF::R_390_TLS_LDM64;
163     case SystemZ::FK_390_TLS_CALL:
164       return ELF::R_390_TLS_LDCALL;
165     }
166     reportError(Loc, "Unsupported thread-local address (local-dynamic)");
167     return 0;
168 
169   case SystemZ::S_TLSGD:
170     assert(!IsPCRel && "TLSGD shouldn't be PC-relative");
171     switch (Kind) {
172     case FK_Data_4:
173       return ELF::R_390_TLS_GD32;
174     case FK_Data_8:
175       return ELF::R_390_TLS_GD64;
176     case SystemZ::FK_390_TLS_CALL:
177       return ELF::R_390_TLS_GDCALL;
178     }
179     reportError(Loc, "Unsupported thread-local address (general-dynamic)");
180     return 0;
181 
182   case SystemZ::S_GOT:
183   case SystemZ::S_GOTENT:
184     if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
185       return ELF::R_390_GOTENT;
186     reportError(Loc, "Only PC-relative GOT accesses are supported for now");
187     return 0;
188 
189   case SystemZ::S_PLT:
190     assert(IsPCRel && "@PLT shouldn't be PC-relative");
191     switch (Kind) {
192     case SystemZ::FK_390_PC12DBL:
193       return ELF::R_390_PLT12DBL;
194     case SystemZ::FK_390_PC16DBL:
195       return ELF::R_390_PLT16DBL;
196     case SystemZ::FK_390_PC24DBL:
197       return ELF::R_390_PLT24DBL;
198     case SystemZ::FK_390_PC32DBL:
199       return ELF::R_390_PLT32DBL;
200     }
201     reportError(Loc, "Unsupported PC-relative PLT address");
202     return 0;
203 
204   default:
205     llvm_unreachable("Modifier not supported");
206   }
207 }
208 
209 bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
210                                                      unsigned Type) const {
211   switch (V.getSpecifier()) {
212   case SystemZ::S_GOT:
213   case SystemZ::S_PLT:
214     return true;
215   default:
216     return false;
217   }
218 }
219 
220 std::unique_ptr<MCObjectTargetWriter>
221 llvm::createSystemZELFObjectWriter(uint8_t OSABI) {
222   return std::make_unique<SystemZELFObjectWriter>(OSABI);
223 }
224