Coverage Report

Created: 2025-12-27 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/keystone/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
Line
Count
Source
1
//===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//
2
//
3
//                     The LLVM Compiler Infrastructure
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 "MCTargetDesc/X86FixupKinds.h"
11
#include "MCTargetDesc/X86MCTargetDesc.h"
12
#include "llvm/MC/MCContext.h"
13
#include "llvm/MC/MCELFObjectWriter.h"
14
#include "llvm/MC/MCExpr.h"
15
#include "llvm/MC/MCValue.h"
16
#include "llvm/Support/ELF.h"
17
#include "llvm/Support/ErrorHandling.h"
18
19
using namespace llvm_ks;
20
21
namespace {
22
  class X86ELFObjectWriter : public MCELFObjectTargetWriter {
23
  public:
24
    X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
25
26
    ~X86ELFObjectWriter() override;
27
28
  protected:
29
    unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
30
                          const MCFixup &Fixup, bool IsPCRel) const override;
31
  };
32
}
33
34
X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
35
                                       uint16_t EMachine)
36
14.9k
    : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
37
                              // Only i386 and IAMCU use Rel instead of RelA.
38
                              /*HasRelocationAddend*/
39
14.9k
                              (EMachine != ELF::EM_386) &&
40
14.9k
                                  (EMachine != ELF::EM_IAMCU)) {}
41
42
X86ELFObjectWriter::~X86ELFObjectWriter()
43
{}
44
45
enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
46
47
static X86_64RelType getType64(unsigned Kind,
48
                               MCSymbolRefExpr::VariantKind &Modifier,
49
5.17k
                               bool &IsPCRel) {
50
5.17k
  switch (Kind) {
51
0
  default:
52
0
    llvm_unreachable("Unimplemented");
53
0
  case X86::reloc_global_offset_table8:
54
0
    Modifier = MCSymbolRefExpr::VK_GOT;
55
0
    IsPCRel = true;
56
0
    return RT64_64;
57
0
  case FK_Data_8:
58
0
    return RT64_64;
59
1
  case X86::reloc_signed_4byte:
60
1
    if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
61
1
      return RT64_32S;
62
0
    return RT64_32;
63
0
  case X86::reloc_global_offset_table:
64
0
    Modifier = MCSymbolRefExpr::VK_GOT;
65
0
    IsPCRel = true;
66
0
    return RT64_32;
67
1.51k
  case FK_Data_4:
68
1.51k
  case FK_PCRel_4:
69
1.51k
  case X86::reloc_riprel_4byte:
70
1.51k
  case X86::reloc_riprel_4byte_movq_load:
71
1.51k
    return RT64_32;
72
0
  case FK_PCRel_2:
73
3.40k
  case FK_Data_2:
74
3.40k
    return RT64_16;
75
0
  case FK_PCRel_1:
76
246
  case FK_Data_1:
77
246
    return RT64_8;
78
5.17k
  }
79
5.17k
}
80
81
0
static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
82
0
  if (Type != RT64_32)
83
0
    Ctx.reportError(Loc,
84
0
                    "32 bit reloc applied to a field with a different size");
85
0
}
86
87
static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
88
                               MCSymbolRefExpr::VariantKind Modifier,
89
194
                               X86_64RelType Type, bool IsPCRel) {
90
194
  switch (Modifier) {
91
0
  default:
92
0
    llvm_unreachable("Unimplemented");
93
194
  case MCSymbolRefExpr::VK_None:
94
194
    switch (Type) {
95
0
    case RT64_64:
96
0
      return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
97
191
    case RT64_32:
98
191
      return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
99
0
    case RT64_32S:
100
0
      return ELF::R_X86_64_32S;
101
1
    case RT64_16:
102
1
      return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
103
2
    case RT64_8:
104
2
      return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
105
194
    }
106
0
  case MCSymbolRefExpr::VK_GOT:
107
0
    switch (Type) {
108
0
    case RT64_64:
109
0
      return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
110
0
    case RT64_32:
111
0
      return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
112
0
    case RT64_32S:
113
0
    case RT64_16:
114
0
    case RT64_8:
115
0
      llvm_unreachable("Unimplemented");
116
0
    }
117
0
  case MCSymbolRefExpr::VK_GOTOFF:
118
0
    assert(Type == RT64_64);
119
0
    assert(!IsPCRel);
120
0
    return ELF::R_X86_64_GOTOFF64;
121
0
  case MCSymbolRefExpr::VK_TPOFF:
122
0
    assert(!IsPCRel);
123
0
    switch (Type) {
124
0
    case RT64_64:
125
0
      return ELF::R_X86_64_TPOFF64;
126
0
    case RT64_32:
127
0
      return ELF::R_X86_64_TPOFF32;
128
0
    case RT64_32S:
129
0
    case RT64_16:
130
0
    case RT64_8:
131
0
      llvm_unreachable("Unimplemented");
132
0
    }
133
0
  case MCSymbolRefExpr::VK_DTPOFF:
134
0
    assert(!IsPCRel);
135
0
    switch (Type) {
136
0
    case RT64_64:
137
0
      return ELF::R_X86_64_DTPOFF64;
138
0
    case RT64_32:
139
0
      return ELF::R_X86_64_DTPOFF32;
140
0
    case RT64_32S:
141
0
    case RT64_16:
142
0
    case RT64_8:
143
0
      llvm_unreachable("Unimplemented");
144
0
    }
145
0
  case MCSymbolRefExpr::VK_SIZE:
146
0
    assert(!IsPCRel);
147
0
    switch (Type) {
148
0
    case RT64_64:
149
0
      return ELF::R_X86_64_SIZE64;
150
0
    case RT64_32:
151
0
      return ELF::R_X86_64_SIZE32;
152
0
    case RT64_32S:
153
0
    case RT64_16:
154
0
    case RT64_8:
155
0
      llvm_unreachable("Unimplemented");
156
0
    }
157
0
  case MCSymbolRefExpr::VK_TLSGD:
158
0
    checkIs32(Ctx, Loc, Type);
159
0
    return ELF::R_X86_64_TLSGD;
160
0
  case MCSymbolRefExpr::VK_GOTTPOFF:
161
0
    checkIs32(Ctx, Loc, Type);
162
0
    return ELF::R_X86_64_GOTTPOFF;
163
0
  case MCSymbolRefExpr::VK_TLSLD:
164
0
    checkIs32(Ctx, Loc, Type);
165
0
    return ELF::R_X86_64_TLSLD;
166
0
  case MCSymbolRefExpr::VK_PLT:
167
0
    checkIs32(Ctx, Loc, Type);
168
0
    return ELF::R_X86_64_PLT32;
169
0
  case MCSymbolRefExpr::VK_GOTPCREL:
170
0
    checkIs32(Ctx, Loc, Type);
171
0
    return ELF::R_X86_64_GOTPCREL;
172
194
  }
173
194
}
174
175
enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
176
177
4.97k
static X86_32RelType getType32(X86_64RelType T) {
178
4.97k
  switch (T) {
179
0
  case RT64_64:
180
0
    llvm_unreachable("Unimplemented");
181
1.32k
  case RT64_32:
182
1.32k
  case RT64_32S:
183
1.32k
    return RT32_32;
184
3.40k
  case RT64_16:
185
3.40k
    return RT32_16;
186
244
  case RT64_8:
187
244
    return RT32_8;
188
4.97k
  }
189
4.97k
  llvm_unreachable("unexpected relocation type!");
190
4.97k
}
191
192
static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier,
193
4.97k
                               X86_32RelType Type, bool IsPCRel) {
194
4.97k
  switch (Modifier) {
195
0
  default:
196
0
    llvm_unreachable("Unimplemented");
197
4.95k
  case MCSymbolRefExpr::VK_None:
198
4.95k
    switch (Type) {
199
1.30k
    case RT32_32:
200
1.30k
      return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
201
3.40k
    case RT32_16:
202
3.40k
      return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
203
244
    case RT32_8:
204
244
      return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
205
4.95k
    }
206
22
  case MCSymbolRefExpr::VK_GOT:
207
22
    assert(Type == RT32_32);
208
22
    return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32;
209
0
  case MCSymbolRefExpr::VK_GOTOFF:
210
0
    assert(Type == RT32_32);
211
0
    assert(!IsPCRel);
212
0
    return ELF::R_386_GOTOFF;
213
0
  case MCSymbolRefExpr::VK_TPOFF:
214
0
    assert(Type == RT32_32);
215
0
    assert(!IsPCRel);
216
0
    return ELF::R_386_TLS_LE_32;
217
0
  case MCSymbolRefExpr::VK_DTPOFF:
218
0
    assert(Type == RT32_32);
219
0
    assert(!IsPCRel);
220
0
    return ELF::R_386_TLS_LDO_32;
221
0
  case MCSymbolRefExpr::VK_TLSGD:
222
0
    assert(Type == RT32_32);
223
0
    assert(!IsPCRel);
224
0
    return ELF::R_386_TLS_GD;
225
0
  case MCSymbolRefExpr::VK_GOTTPOFF:
226
0
    assert(Type == RT32_32);
227
0
    assert(!IsPCRel);
228
0
    return ELF::R_386_TLS_IE_32;
229
0
  case MCSymbolRefExpr::VK_PLT:
230
0
    assert(Type == RT32_32);
231
0
    return ELF::R_386_PLT32;
232
0
  case MCSymbolRefExpr::VK_INDNTPOFF:
233
0
    assert(Type == RT32_32);
234
0
    assert(!IsPCRel);
235
0
    return ELF::R_386_TLS_IE;
236
0
  case MCSymbolRefExpr::VK_NTPOFF:
237
0
    assert(Type == RT32_32);
238
0
    assert(!IsPCRel);
239
0
    return ELF::R_386_TLS_LE;
240
0
  case MCSymbolRefExpr::VK_GOTNTPOFF:
241
0
    assert(Type == RT32_32);
242
0
    assert(!IsPCRel);
243
0
    return ELF::R_386_TLS_GOTIE;
244
0
  case MCSymbolRefExpr::VK_TLSLDM:
245
0
    assert(Type == RT32_32);
246
0
    assert(!IsPCRel);
247
0
    return ELF::R_386_TLS_LDM;
248
4.97k
  }
249
4.97k
}
250
251
unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
252
                                          const MCFixup &Fixup,
253
5.17k
                                          bool IsPCRel) const {
254
5.17k
  MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
255
5.17k
  X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel);
256
5.17k
  if (getEMachine() == ELF::EM_X86_64)
257
194
    return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel);
258
259
5.17k
  assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
260
4.97k
         "Unsupported ELF machine type.");
261
4.97k
  return getRelocType32(Modifier, getType32(Type), IsPCRel);
262
4.97k
}
263
264
MCObjectWriter *llvm_ks::createX86ELFObjectWriter(raw_pwrite_stream &OS,
265
                                               bool IsELF64, uint8_t OSABI,
266
14.9k
                                               uint16_t EMachine) {
267
14.9k
  MCELFObjectTargetWriter *MOTW =
268
14.9k
    new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
269
14.9k
  return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
270
14.9k
}