Coverage Report

Created: 2025-11-16 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/keystone/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
Line
Count
Source
1
//===-- MipsELFObjectWriter.cpp - Mips 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/MipsBaseInfo.h"
11
#include "MCTargetDesc/MipsFixupKinds.h"
12
#include "MCTargetDesc/MipsMCTargetDesc.h"
13
#include "llvm/ADT/STLExtras.h"
14
#include "llvm/MC/MCAssembler.h"
15
#include "llvm/MC/MCELFObjectWriter.h"
16
#include "llvm/MC/MCExpr.h"
17
#include "llvm/MC/MCSection.h"
18
#include "llvm/MC/MCSymbolELF.h"
19
#include "llvm/MC/MCValue.h"
20
#include "llvm/Support/ErrorHandling.h"
21
#include <list>
22
23
using namespace llvm_ks;
24
25
namespace {
26
// A helper structure based on ELFRelocationEntry, used for sorting entries in
27
// the relocation table.
28
struct MipsRelocationEntry {
29
  MipsRelocationEntry(const ELFRelocationEntry &R)
30
0
      : R(R), SortOffset(R.Offset), HasMatchingHi(false) {}
31
  const ELFRelocationEntry R;
32
  // SortOffset equals R.Offset except for the *HI16 relocations, for which it
33
  // will be set based on the R.Offset of the matching *LO16 relocation.
34
  int64_t SortOffset;
35
  // True when this is a *LO16 relocation chosen as a match for a *HI16
36
  // relocation.
37
  bool HasMatchingHi;
38
};
39
40
  class MipsELFObjectWriter : public MCELFObjectTargetWriter {
41
  public:
42
    MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
43
                        bool _isN64, bool IsLittleEndian);
44
45
    ~MipsELFObjectWriter() override;
46
47
    unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
48
                          const MCFixup &Fixup, bool IsPCRel) const override;
49
    bool needsRelocateWithSymbol(const MCSymbol &Sym,
50
                                 unsigned Type) const override;
51
    virtual void sortRelocs(const MCAssembler &Asm,
52
                            std::vector<ELFRelocationEntry> &Relocs) override;
53
  };
54
}
55
56
MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
57
                                         bool _isN64, bool IsLittleEndian)
58
4.50k
    : MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS,
59
4.50k
                              /*HasRelocationAddend*/ _isN64,
60
4.50k
                              /*IsN64*/ _isN64) {}
61
62
MipsELFObjectWriter::~MipsELFObjectWriter() {}
63
64
unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
65
                                           const MCValue &Target,
66
                                           const MCFixup &Fixup,
67
7.30k
                                           bool IsPCRel) const {
68
  // Determine the type of the relocation.
69
7.30k
  unsigned Kind = (unsigned)Fixup.getKind();
70
71
7.30k
  switch (Kind) {
72
0
  case Mips::fixup_Mips_NONE:
73
0
    return ELF::R_MIPS_NONE;
74
0
  case Mips::fixup_Mips_16:
75
49
  case FK_Data_2:
76
49
    return IsPCRel ? ELF::R_MIPS_PC16 : ELF::R_MIPS_16;
77
165
  case Mips::fixup_Mips_32:
78
6.38k
  case FK_Data_4:
79
6.38k
    return IsPCRel ? ELF::R_MIPS_PC32 : ELF::R_MIPS_32;
80
7.30k
  }
81
82
874
  if (IsPCRel) {
83
67
    switch (Kind) {
84
0
    case Mips::fixup_Mips_Branch_PCRel:
85
67
    case Mips::fixup_Mips_PC16:
86
67
      return ELF::R_MIPS_PC16;
87
0
    case Mips::fixup_MICROMIPS_PC7_S1:
88
0
      return ELF::R_MICROMIPS_PC7_S1;
89
0
    case Mips::fixup_MICROMIPS_PC10_S1:
90
0
      return ELF::R_MICROMIPS_PC10_S1;
91
0
    case Mips::fixup_MICROMIPS_PC16_S1:
92
0
      return ELF::R_MICROMIPS_PC16_S1;
93
0
    case Mips::fixup_MIPS_PC19_S2:
94
0
      return ELF::R_MIPS_PC19_S2;
95
0
    case Mips::fixup_MIPS_PC18_S3:
96
0
      return ELF::R_MIPS_PC18_S3;
97
0
    case Mips::fixup_MIPS_PC21_S2:
98
0
      return ELF::R_MIPS_PC21_S2;
99
0
    case Mips::fixup_MIPS_PC26_S2:
100
0
      return ELF::R_MIPS_PC26_S2;
101
0
    case Mips::fixup_MIPS_PCHI16:
102
0
      return ELF::R_MIPS_PCHI16;
103
0
    case Mips::fixup_MIPS_PCLO16:
104
0
      return ELF::R_MIPS_PCLO16;
105
67
    }
106
107
67
    llvm_unreachable("invalid PC-relative fixup kind!");
108
67
  }
109
110
807
  switch (Kind) {
111
0
  case Mips::fixup_Mips_64:
112
55
  case FK_Data_8:
113
55
    return ELF::R_MIPS_64;
114
0
  case FK_GPRel_4:
115
0
    if (isN64()) {
116
0
      unsigned Type = (unsigned)ELF::R_MIPS_NONE;
117
0
      Type = setRType((unsigned)ELF::R_MIPS_GPREL32, Type);
118
0
      Type = setRType2((unsigned)ELF::R_MIPS_64, Type);
119
0
      Type = setRType3((unsigned)ELF::R_MIPS_NONE, Type);
120
0
      return Type;
121
0
    }
122
0
    return ELF::R_MIPS_GPREL32;
123
0
  case Mips::fixup_Mips_GPREL16:
124
0
    return ELF::R_MIPS_GPREL16;
125
446
  case Mips::fixup_Mips_26:
126
446
    return ELF::R_MIPS_26;
127
1
  case Mips::fixup_Mips_CALL16:
128
1
    return ELF::R_MIPS_CALL16;
129
0
  case Mips::fixup_Mips_GOT_Global:
130
0
  case Mips::fixup_Mips_GOT_Local:
131
0
    return ELF::R_MIPS_GOT16;
132
160
  case Mips::fixup_Mips_HI16:
133
160
    return ELF::R_MIPS_HI16;
134
144
  case Mips::fixup_Mips_LO16:
135
144
    return ELF::R_MIPS_LO16;
136
0
  case Mips::fixup_Mips_TLSGD:
137
0
    return ELF::R_MIPS_TLS_GD;
138
0
  case Mips::fixup_Mips_GOTTPREL:
139
0
    return ELF::R_MIPS_TLS_GOTTPREL;
140
0
  case Mips::fixup_Mips_TPREL_HI:
141
0
    return ELF::R_MIPS_TLS_TPREL_HI16;
142
0
  case Mips::fixup_Mips_TPREL_LO:
143
0
    return ELF::R_MIPS_TLS_TPREL_LO16;
144
0
  case Mips::fixup_Mips_TLSLDM:
145
0
    return ELF::R_MIPS_TLS_LDM;
146
0
  case Mips::fixup_Mips_DTPREL_HI:
147
0
    return ELF::R_MIPS_TLS_DTPREL_HI16;
148
0
  case Mips::fixup_Mips_DTPREL_LO:
149
0
    return ELF::R_MIPS_TLS_DTPREL_LO16;
150
0
  case Mips::fixup_Mips_GOT_PAGE:
151
0
    return ELF::R_MIPS_GOT_PAGE;
152
0
  case Mips::fixup_Mips_GOT_OFST:
153
0
    return ELF::R_MIPS_GOT_OFST;
154
1
  case Mips::fixup_Mips_GOT_DISP:
155
1
    return ELF::R_MIPS_GOT_DISP;
156
0
  case Mips::fixup_Mips_GPOFF_HI: {
157
0
    unsigned Type = (unsigned)ELF::R_MIPS_NONE;
158
0
    Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type);
159
0
    Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type);
160
0
    Type = setRType3((unsigned)ELF::R_MIPS_HI16, Type);
161
0
    return Type;
162
0
  }
163
0
  case Mips::fixup_Mips_GPOFF_LO: {
164
0
    unsigned Type = (unsigned)ELF::R_MIPS_NONE;
165
0
    Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type);
166
0
    Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type);
167
0
    Type = setRType3((unsigned)ELF::R_MIPS_LO16, Type);
168
0
    return Type;
169
0
  }
170
0
  case Mips::fixup_Mips_HIGHER:
171
0
    return ELF::R_MIPS_HIGHER;
172
0
  case Mips::fixup_Mips_HIGHEST:
173
0
    return ELF::R_MIPS_HIGHEST;
174
0
  case Mips::fixup_Mips_GOT_HI16:
175
0
    return ELF::R_MIPS_GOT_HI16;
176
0
  case Mips::fixup_Mips_GOT_LO16:
177
0
    return ELF::R_MIPS_GOT_LO16;
178
0
  case Mips::fixup_Mips_CALL_HI16:
179
0
    return ELF::R_MIPS_CALL_HI16;
180
0
  case Mips::fixup_Mips_CALL_LO16:
181
0
    return ELF::R_MIPS_CALL_LO16;
182
0
  case Mips::fixup_MICROMIPS_26_S1:
183
0
    return ELF::R_MICROMIPS_26_S1;
184
0
  case Mips::fixup_MICROMIPS_HI16:
185
0
    return ELF::R_MICROMIPS_HI16;
186
0
  case Mips::fixup_MICROMIPS_LO16:
187
0
    return ELF::R_MICROMIPS_LO16;
188
0
  case Mips::fixup_MICROMIPS_GOT16:
189
0
    return ELF::R_MICROMIPS_GOT16;
190
0
  case Mips::fixup_MICROMIPS_CALL16:
191
0
    return ELF::R_MICROMIPS_CALL16;
192
0
  case Mips::fixup_MICROMIPS_GOT_DISP:
193
0
    return ELF::R_MICROMIPS_GOT_DISP;
194
0
  case Mips::fixup_MICROMIPS_GOT_PAGE:
195
0
    return ELF::R_MICROMIPS_GOT_PAGE;
196
0
  case Mips::fixup_MICROMIPS_GOT_OFST:
197
0
    return ELF::R_MICROMIPS_GOT_OFST;
198
0
  case Mips::fixup_MICROMIPS_TLS_GD:
199
0
    return ELF::R_MICROMIPS_TLS_GD;
200
0
  case Mips::fixup_MICROMIPS_TLS_LDM:
201
0
    return ELF::R_MICROMIPS_TLS_LDM;
202
0
  case Mips::fixup_MICROMIPS_TLS_DTPREL_HI16:
203
0
    return ELF::R_MICROMIPS_TLS_DTPREL_HI16;
204
0
  case Mips::fixup_MICROMIPS_TLS_DTPREL_LO16:
205
0
    return ELF::R_MICROMIPS_TLS_DTPREL_LO16;
206
0
  case Mips::fixup_MICROMIPS_TLS_TPREL_HI16:
207
0
    return ELF::R_MICROMIPS_TLS_TPREL_HI16;
208
0
  case Mips::fixup_MICROMIPS_TLS_TPREL_LO16:
209
0
    return ELF::R_MICROMIPS_TLS_TPREL_LO16;
210
807
  }
211
212
807
  llvm_unreachable("invalid fixup kind!");
213
807
}
214
215
// Sort entries by SortOffset in descending order.
216
// When there are more *HI16 relocs paired with one *LO16 reloc, the 2nd rule
217
// sorts them in ascending order of R.Offset.
218
static int cmpRelMips(const MipsRelocationEntry *AP,
219
0
                      const MipsRelocationEntry *BP) {
220
0
  const MipsRelocationEntry &A = *AP;
221
0
  const MipsRelocationEntry &B = *BP;
222
0
  if (A.SortOffset != B.SortOffset)
223
0
    return B.SortOffset - A.SortOffset;
224
0
  if (A.R.Offset != B.R.Offset)
225
0
    return A.R.Offset - B.R.Offset;
226
0
  if (B.R.Type != A.R.Type)
227
0
    return B.R.Type - A.R.Type;
228
  //llvm_unreachable("ELFRelocs might be unstable!");
229
0
  return 0;
230
0
}
231
232
// For the given Reloc.Type, return the matching relocation type, as in the
233
// table below.
234
static unsigned getMatchingLoType(const MCAssembler &Asm,
235
0
                                  const ELFRelocationEntry &Reloc) {
236
0
  unsigned Type = Reloc.Type;
237
0
  if (Type == ELF::R_MIPS_HI16)
238
0
    return ELF::R_MIPS_LO16;
239
0
  if (Type == ELF::R_MICROMIPS_HI16)
240
0
    return ELF::R_MICROMIPS_LO16;
241
0
  if (Type == ELF::R_MIPS16_HI16)
242
0
    return ELF::R_MIPS16_LO16;
243
244
0
  if (Reloc.Symbol->getBinding() != ELF::STB_LOCAL)
245
0
    return ELF::R_MIPS_NONE;
246
247
0
  if (Type == ELF::R_MIPS_GOT16)
248
0
    return ELF::R_MIPS_LO16;
249
0
  if (Type == ELF::R_MICROMIPS_GOT16)
250
0
    return ELF::R_MICROMIPS_LO16;
251
0
  if (Type == ELF::R_MIPS16_GOT16)
252
0
    return ELF::R_MIPS16_LO16;
253
254
0
  return ELF::R_MIPS_NONE;
255
0
}
256
257
// Return true if First needs a matching *LO16, its matching *LO16 type equals
258
// Second's type and both relocations are against the same symbol.
259
static bool areMatchingHiAndLo(const MCAssembler &Asm,
260
                               const ELFRelocationEntry &First,
261
0
                               const ELFRelocationEntry &Second) {
262
0
  return getMatchingLoType(Asm, First) != ELF::R_MIPS_NONE &&
263
0
         getMatchingLoType(Asm, First) == Second.Type &&
264
0
         First.Symbol && First.Symbol == Second.Symbol;
265
0
}
266
267
// Return true if MipsRelocs[Index] is a *LO16 preceded by a matching *HI16.
268
static bool
269
isPrecededByMatchingHi(const MCAssembler &Asm, uint32_t Index,
270
0
                       std::vector<MipsRelocationEntry> &MipsRelocs) {
271
0
  return Index < MipsRelocs.size() - 1 &&
272
0
         areMatchingHiAndLo(Asm, MipsRelocs[Index + 1].R, MipsRelocs[Index].R);
273
0
}
274
275
// Return true if MipsRelocs[Index] is a *LO16 not preceded by a matching *HI16
276
// and not chosen by a *HI16 as a match.
277
static bool isFreeLo(const MCAssembler &Asm, uint32_t Index,
278
0
                     std::vector<MipsRelocationEntry> &MipsRelocs) {
279
0
  return Index < MipsRelocs.size() && !MipsRelocs[Index].HasMatchingHi &&
280
0
         !isPrecededByMatchingHi(Asm, Index, MipsRelocs);
281
0
}
282
283
// Lo is chosen as a match for Hi, set their fields accordingly.
284
// Mips instructions have fixed length of at least two bytes (two for
285
// micromips/mips16, four for mips32/64), so we can set HI's SortOffset to
286
// matching LO's Offset minus one to simplify the sorting function.
287
0
static void setMatch(MipsRelocationEntry &Hi, MipsRelocationEntry &Lo) {
288
0
  Lo.HasMatchingHi = true;
289
0
  Hi.SortOffset = Lo.R.Offset - 1;
290
0
}
291
292
// We sort relocation table entries by offset, except for one additional rule
293
// required by MIPS ABI: every *HI16 relocation must be immediately followed by
294
// the corresponding *LO16 relocation. We also support a GNU extension that
295
// allows more *HI16s paired with one *LO16.
296
//
297
// *HI16 relocations and their matching *LO16 are:
298
//
299
// +---------------------------------------------+-------------------+
300
// |               *HI16                         |  matching *LO16   |
301
// |---------------------------------------------+-------------------|
302
// |  R_MIPS_HI16, local R_MIPS_GOT16            |    R_MIPS_LO16    |
303
// |  R_MICROMIPS_HI16, local R_MICROMIPS_GOT16  | R_MICROMIPS_LO16  |
304
// |  R_MIPS16_HI16, local R_MIPS16_GOT16        |  R_MIPS16_LO16    |
305
// +---------------------------------------------+-------------------+
306
//
307
// (local R_*_GOT16 meaning R_*_GOT16 against the local symbol.)
308
//
309
// To handle *HI16 and *LO16 relocations, the linker needs a combined addend
310
// ("AHL") calculated from both *HI16 ("AHI") and *LO16 ("ALO") relocations:
311
// AHL = (AHI << 16) + (short)ALO;
312
//
313
// We are reusing gnu as sorting algorithm so we are emitting the relocation
314
// table sorted the same way as gnu as would sort it, for easier comparison of
315
// the generated .o files.
316
//
317
// The logic is:
318
// search the table (starting from the highest offset and going back to zero)
319
// for all *HI16 relocations that don't have a matching *LO16.
320
// For every such HI, find a matching LO with highest offset that isn't already
321
// matched with another HI. If there are no free LOs, match it with the first
322
// found (starting from lowest offset).
323
// When there are more HIs matched with one LO, sort them in descending order by
324
// offset.
325
//
326
// In other words, when searching for a matching LO:
327
// - don't look for a 'better' match for the HIs that are already followed by a
328
//   matching LO;
329
// - prefer LOs without a pair;
330
// - prefer LOs with higher offset;
331
332
0
static int cmpRel(const ELFRelocationEntry *AP, const ELFRelocationEntry *BP) {
333
0
  const ELFRelocationEntry &A = *AP;
334
0
  const ELFRelocationEntry &B = *BP;
335
0
  if (A.Offset < B.Offset)
336
0
    return 1;
337
0
  if (A.Offset > B.Offset)
338
0
    return -1;
339
0
  assert(B.Type != A.Type && "We don't have a total order");
340
0
  return A.Type - B.Type;
341
0
}
342
343
void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
344
0
                                     std::vector<ELFRelocationEntry> &Relocs) {
345
0
  if (Relocs.size() < 2)
346
0
    return;
347
348
  // Sorts entries by Offset in descending order.
349
0
  array_pod_sort(Relocs.begin(), Relocs.end(), cmpRel);
350
351
  // Init MipsRelocs from Relocs.
352
0
  std::vector<MipsRelocationEntry> MipsRelocs;
353
0
  for (unsigned I = 0, E = Relocs.size(); I != E; ++I)
354
0
    MipsRelocs.push_back(MipsRelocationEntry(Relocs[I]));
355
356
  // Find a matching LO for all HIs that need it.
357
0
  for (int32_t I = 0, E = MipsRelocs.size(); I != E; ++I) {
358
0
    if (getMatchingLoType(Asm, MipsRelocs[I].R) == ELF::R_MIPS_NONE ||
359
0
        (I > 0 && isPrecededByMatchingHi(Asm, I - 1, MipsRelocs)))
360
0
      continue;
361
362
0
    int32_t MatchedLoIndex = -1;
363
364
    // Search the list in the ascending order of Offset.
365
0
    for (int32_t J = MipsRelocs.size() - 1, N = -1; J != N; --J) {
366
      // check for a match
367
0
      if (areMatchingHiAndLo(Asm, MipsRelocs[I].R, MipsRelocs[J].R) &&
368
0
          (MatchedLoIndex == -1 || // first match
369
           // or we already have a match,
370
           // but this one is with higher offset and it's free
371
0
           (MatchedLoIndex > J && isFreeLo(Asm, J, MipsRelocs))))
372
0
        MatchedLoIndex = J;
373
0
    }
374
375
0
    if (MatchedLoIndex != -1)
376
      // We have a match.
377
0
      setMatch(MipsRelocs[I], MipsRelocs[MatchedLoIndex]);
378
0
  }
379
380
  // SortOffsets are calculated, call the sorting function.
381
0
  array_pod_sort(MipsRelocs.begin(), MipsRelocs.end(), cmpRelMips);
382
383
  // Copy sorted MipsRelocs back to Relocs.
384
0
  for (unsigned I = 0, E = MipsRelocs.size(); I != E; ++I)
385
0
    Relocs[I] = MipsRelocs[I].R;
386
0
}
387
388
bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
389
6.66k
                                                  unsigned Type) const {
390
  // FIXME: This is extremely conservative. This really needs to use a
391
  // whitelist with a clear explanation for why each realocation needs to
392
  // point to the symbol, not to the section.
393
6.66k
  switch (Type) {
394
51
  default:
395
51
    return true;
396
397
0
  case ELF::R_MIPS_GOT16:
398
0
  case ELF::R_MIPS16_GOT16:
399
0
  case ELF::R_MICROMIPS_GOT16:
400
0
    llvm_unreachable("Should have been handled already");
401
402
  // These relocations might be paired with another relocation. The pairing is
403
  // done by the static linker by matching the symbol. Since we only see one
404
  // relocation at a time, we have to force them to relocate with a symbol to
405
  // avoid ending up with a pair where one points to a section and another
406
  // points to a symbol.
407
160
  case ELF::R_MIPS_HI16:
408
160
  case ELF::R_MIPS16_HI16:
409
160
  case ELF::R_MICROMIPS_HI16:
410
304
  case ELF::R_MIPS_LO16:
411
304
  case ELF::R_MIPS16_LO16:
412
304
  case ELF::R_MICROMIPS_LO16:
413
304
    return true;
414
415
5.80k
  case ELF::R_MIPS_32:
416
5.80k
    if (cast<MCSymbolELF>(Sym).getOther() & ELF::STO_MIPS_MICROMIPS)
417
0
      return true;
418
    // falltrough
419
6.25k
  case ELF::R_MIPS_26:
420
6.30k
  case ELF::R_MIPS_64:
421
6.30k
  case ELF::R_MIPS_GPREL16:
422
6.30k
    return false;
423
6.66k
  }
424
6.66k
}
425
426
MCObjectWriter *llvm_ks::createMipsELFObjectWriter(raw_pwrite_stream &OS,
427
                                                uint8_t OSABI,
428
                                                bool IsLittleEndian,
429
4.50k
                                                bool Is64Bit) {
430
4.50k
  MCELFObjectTargetWriter *MOTW =
431
4.50k
      new MipsELFObjectWriter(Is64Bit, OSABI, Is64Bit, IsLittleEndian);
432
4.50k
  return createELFObjectWriter(MOTW, OS, IsLittleEndian);
433
4.50k
}