Coverage Report

Created: 2023-09-25 06:27

/src/keystone/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- AArch64AsmBackend.cpp - AArch64 Assembler Backend -----------------===//
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 "llvm/MC/MCRegisterInfo.h"
11
#include "Utils/AArch64BaseInfo.h"
12
#include "MCTargetDesc/AArch64MCTargetDesc.h"
13
#include "MCTargetDesc/AArch64FixupKinds.h"
14
#include "llvm/ADT/Triple.h"
15
#include "llvm/MC/MCAsmBackend.h"
16
#include "llvm/MC/MCDirectives.h"
17
#include "llvm/MC/MCELFObjectWriter.h"
18
#include "llvm/MC/MCFixupKindInfo.h"
19
#include "llvm/MC/MCObjectWriter.h"
20
#include "llvm/MC/MCSectionELF.h"
21
#include "llvm/MC/MCSectionMachO.h"
22
#include "llvm/MC/MCValue.h"
23
#include "llvm/Support/ErrorHandling.h"
24
#include "llvm/Support/MachO.h"
25
26
#include <keystone/keystone.h>
27
28
using namespace llvm_ks;
29
30
namespace {
31
32
class AArch64AsmBackend : public MCAsmBackend {
33
  static const unsigned PCRelFlagVal =
34
      MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel;
35
public:
36
  bool IsLittleEndian;
37
38
public:
39
  AArch64AsmBackend(const Target &T, bool IsLittleEndian)
40
2.03k
     : MCAsmBackend(), IsLittleEndian(IsLittleEndian) {}
41
42
1.87k
  unsigned getNumFixupKinds() const override {
43
1.87k
    return AArch64::NumTargetFixupKinds;
44
1.87k
  }
45
46
6.68k
  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
47
6.68k
    const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = {
48
      // This table *must* be in the order that the fixup_* kinds are defined in
49
      // AArch64FixupKinds.h.
50
      //
51
      // Name                           Offset (bits) Size (bits)     Flags
52
6.68k
      { "fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal },
53
6.68k
      { "fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal },
54
6.68k
      { "fixup_aarch64_add_imm12", 10, 12, 0 },
55
6.68k
      { "fixup_aarch64_ldst_imm12_scale1", 10, 12, 0 },
56
6.68k
      { "fixup_aarch64_ldst_imm12_scale2", 10, 12, 0 },
57
6.68k
      { "fixup_aarch64_ldst_imm12_scale4", 10, 12, 0 },
58
6.68k
      { "fixup_aarch64_ldst_imm12_scale8", 10, 12, 0 },
59
6.68k
      { "fixup_aarch64_ldst_imm12_scale16", 10, 12, 0 },
60
6.68k
      { "fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal },
61
6.68k
      { "fixup_aarch64_movw", 5, 16, 0 },
62
6.68k
      { "fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal },
63
6.68k
      { "fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal },
64
6.68k
      { "fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal },
65
6.68k
      { "fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal },
66
6.68k
      { "fixup_aarch64_tlsdesc_call", 0, 0, 0 }
67
6.68k
    };
68
69
6.68k
    if (Kind < FirstTargetFixupKind)
70
4.80k
      return MCAsmBackend::getFixupKindInfo(Kind);
71
72
1.87k
    assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
73
1.87k
           "Invalid kind!");
74
0
    return Infos[Kind - FirstTargetFixupKind];
75
6.68k
  }
76
77
  void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
78
                  uint64_t Value, bool IsPCRel, unsigned int &KsError) const override;
79
80
  bool mayNeedRelaxation(const MCInst &Inst) const override;
81
  bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
82
                            const MCRelaxableFragment *DF,
83
                            const MCAsmLayout &Layout, unsigned &KsError) const override;
84
  void relaxInstruction(const MCInst &Inst, MCInst &Res) const override;
85
  bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
86
87
0
  void HandleAssemblerFlag(MCAssemblerFlag Flag) {}
88
89
0
  unsigned getPointerSize() const { return 8; }
90
91
  unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const;
92
};
93
94
} // end anonymous namespace
95
96
/// \brief The number of bytes the fixup may change.
97
1.77k
static unsigned getFixupKindNumBytes(unsigned Kind) {
98
1.77k
  switch (Kind) {
99
0
  default:
100
0
    llvm_unreachable("Unknown fixup kind!");
101
102
0
  case AArch64::fixup_aarch64_tlsdesc_call:
103
0
    return 0;
104
105
0
  case FK_Data_1:
106
0
    return 1;
107
108
33
  case FK_Data_2:
109
33
  case AArch64::fixup_aarch64_movw:
110
33
    return 2;
111
112
0
  case AArch64::fixup_aarch64_pcrel_branch14:
113
0
  case AArch64::fixup_aarch64_add_imm12:
114
0
  case AArch64::fixup_aarch64_ldst_imm12_scale1:
115
0
  case AArch64::fixup_aarch64_ldst_imm12_scale2:
116
0
  case AArch64::fixup_aarch64_ldst_imm12_scale4:
117
0
  case AArch64::fixup_aarch64_ldst_imm12_scale8:
118
0
  case AArch64::fixup_aarch64_ldst_imm12_scale16:
119
1
  case AArch64::fixup_aarch64_ldr_pcrel_imm19:
120
179
  case AArch64::fixup_aarch64_pcrel_branch19:
121
179
    return 3;
122
123
0
  case AArch64::fixup_aarch64_pcrel_adr_imm21:
124
0
  case AArch64::fixup_aarch64_pcrel_adrp_imm21:
125
108
  case AArch64::fixup_aarch64_pcrel_branch26:
126
402
  case AArch64::fixup_aarch64_pcrel_call26:
127
1.56k
  case FK_Data_4:
128
1.56k
    return 4;
129
130
0
  case FK_Data_8:
131
0
    return 8;
132
1.77k
  }
133
1.77k
}
134
135
0
static unsigned AdrImmBits(unsigned Value) {
136
0
  unsigned lo2 = Value & 0x3;
137
0
  unsigned hi19 = (Value & 0x1ffffc) >> 2;
138
0
  return (hi19 << 5) | (lo2 << 29);
139
0
}
140
141
1.17k
static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
142
1.17k
  int64_t SignedValue = static_cast<int64_t>(Value);
143
1.17k
  switch (Kind) {
144
0
  default:
145
0
    llvm_unreachable("Unknown fixup kind!");
146
0
  case AArch64::fixup_aarch64_pcrel_adr_imm21:
147
0
    if (SignedValue > 2097151 || SignedValue < -2097152)
148
0
      report_fatal_error("fixup value out of range");
149
0
    return AdrImmBits(Value & 0x1fffffULL);
150
0
  case AArch64::fixup_aarch64_pcrel_adrp_imm21:
151
0
    return AdrImmBits((Value & 0x1fffff000ULL) >> 12);
152
0
  case AArch64::fixup_aarch64_ldr_pcrel_imm19:
153
18
  case AArch64::fixup_aarch64_pcrel_branch19:
154
    // Signed 21-bit immediate
155
18
    if (SignedValue > 2097151 || SignedValue < -2097152)
156
0
      report_fatal_error("fixup value out of range");
157
    // Low two bits are not encoded.
158
18
    return (Value >> 2) & 0x7ffff;
159
0
  case AArch64::fixup_aarch64_add_imm12:
160
0
  case AArch64::fixup_aarch64_ldst_imm12_scale1:
161
    // Unsigned 12-bit immediate
162
0
    if (Value >= 0x1000)
163
0
      report_fatal_error("invalid imm12 fixup value");
164
0
    return Value;
165
0
  case AArch64::fixup_aarch64_ldst_imm12_scale2:
166
    // Unsigned 12-bit immediate which gets multiplied by 2
167
0
    if (Value & 1 || Value >= 0x2000)
168
0
      report_fatal_error("invalid imm12 fixup value");
169
0
    return Value >> 1;
170
0
  case AArch64::fixup_aarch64_ldst_imm12_scale4:
171
    // Unsigned 12-bit immediate which gets multiplied by 4
172
0
    if (Value & 3 || Value >= 0x4000)
173
0
      report_fatal_error("invalid imm12 fixup value");
174
0
    return Value >> 2;
175
0
  case AArch64::fixup_aarch64_ldst_imm12_scale8:
176
    // Unsigned 12-bit immediate which gets multiplied by 8
177
0
    if (Value & 7 || Value >= 0x8000)
178
0
      report_fatal_error("invalid imm12 fixup value");
179
0
    return Value >> 3;
180
0
  case AArch64::fixup_aarch64_ldst_imm12_scale16:
181
    // Unsigned 12-bit immediate which gets multiplied by 16
182
0
    if (Value & 15 || Value >= 0x10000)
183
0
      report_fatal_error("invalid imm12 fixup value");
184
0
    return Value >> 4;
185
0
  case AArch64::fixup_aarch64_movw:
186
0
    report_fatal_error("no resolvable MOVZ/MOVK fixups supported yet");
187
0
    return Value;
188
0
  case AArch64::fixup_aarch64_pcrel_branch14:
189
    // Signed 16-bit immediate
190
0
    if (SignedValue > 32767 || SignedValue < -32768)
191
0
      report_fatal_error("fixup value out of range");
192
    // Low two bits are not encoded (4-byte alignment assumed).
193
0
    if (Value & 0x3)
194
0
      report_fatal_error("fixup not sufficiently aligned");
195
0
    return (Value >> 2) & 0x3fff;
196
0
  case AArch64::fixup_aarch64_pcrel_branch26:
197
64
  case AArch64::fixup_aarch64_pcrel_call26:
198
    // Signed 28-bit immediate
199
64
    if (SignedValue > 134217727 || SignedValue < -134217728)
200
0
      report_fatal_error("fixup value out of range");
201
    // Low two bits are not encoded (4-byte alignment assumed).
202
64
    if (Value & 0x3)
203
0
      report_fatal_error("fixup not sufficiently aligned");
204
64
    return (Value >> 2) & 0x3ffffff;
205
0
  case FK_Data_1:
206
33
  case FK_Data_2:
207
1.09k
  case FK_Data_4:
208
1.09k
  case FK_Data_8:
209
1.09k
    return Value;
210
1.17k
  }
211
1.17k
}
212
213
/// getFixupKindContainereSizeInBytes - The number of bytes of the
214
/// container involved in big endian or 0 if the item is little endian
215
1.17k
unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) const {
216
1.17k
  if (IsLittleEndian)
217
1.17k
    return 0;
218
219
0
  switch (Kind) {
220
0
  default:
221
0
    llvm_unreachable("Unknown fixup kind!");
222
223
0
  case FK_Data_1:
224
0
    return 1;
225
0
  case FK_Data_2:
226
0
    return 2;
227
0
  case FK_Data_4:
228
0
    return 4;
229
0
  case FK_Data_8:
230
0
    return 8;
231
232
0
  case AArch64::fixup_aarch64_tlsdesc_call:
233
0
  case AArch64::fixup_aarch64_movw:
234
0
  case AArch64::fixup_aarch64_pcrel_branch14:
235
0
  case AArch64::fixup_aarch64_add_imm12:
236
0
  case AArch64::fixup_aarch64_ldst_imm12_scale1:
237
0
  case AArch64::fixup_aarch64_ldst_imm12_scale2:
238
0
  case AArch64::fixup_aarch64_ldst_imm12_scale4:
239
0
  case AArch64::fixup_aarch64_ldst_imm12_scale8:
240
0
  case AArch64::fixup_aarch64_ldst_imm12_scale16:
241
0
  case AArch64::fixup_aarch64_ldr_pcrel_imm19:
242
0
  case AArch64::fixup_aarch64_pcrel_branch19:
243
0
  case AArch64::fixup_aarch64_pcrel_adr_imm21:
244
0
  case AArch64::fixup_aarch64_pcrel_adrp_imm21:
245
0
  case AArch64::fixup_aarch64_pcrel_branch26:
246
0
  case AArch64::fixup_aarch64_pcrel_call26:
247
    // Instructions are always little endian
248
0
    return 0;
249
0
  }
250
0
}
251
252
void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
253
                                   unsigned DataSize, uint64_t Value,
254
1.77k
                                   bool IsPCRel, unsigned int &KsError) const {
255
1.77k
  unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
256
1.77k
  if (!Value)
257
604
    return; // Doesn't change encoding.
258
1.17k
  MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
259
  // Apply any target-specific value adjustments.
260
1.17k
  Value = adjustFixupValue(Fixup.getKind(), Value);
261
262
  // Shift the value into position.
263
1.17k
  Value <<= Info.TargetOffset;
264
265
1.17k
  unsigned Offset = Fixup.getOffset();
266
  //assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
267
1.17k
  if (Offset + NumBytes > DataSize) {
268
0
      KsError = KS_ERR_ASM_FIXUP_INVALID;
269
0
      return;
270
0
  }
271
272
  // Used to point to big endian bytes.
273
1.17k
  unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind());
274
275
  // For each byte of the fragment that the fixup touches, mask in the
276
  // bits from the fixup value.
277
1.17k
  if (FulleSizeInBytes == 0) {
278
    // Handle as little-endian
279
5.79k
    for (unsigned i = 0; i != NumBytes; ++i) {
280
4.61k
      Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
281
4.61k
    }
282
1.17k
  } else {
283
    // Handle as big-endian
284
    //assert((Offset + FulleSizeInBytes) <= DataSize && "Invalid fixup size!");
285
    //assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!");
286
0
    if ((Offset + FulleSizeInBytes) > DataSize ||
287
0
            NumBytes > FulleSizeInBytes) {
288
0
        KsError = KS_ERR_ASM_FIXUP_INVALID;
289
0
        return;
290
0
    }
291
0
    for (unsigned i = 0; i != NumBytes; ++i) {
292
0
      unsigned Idx = FulleSizeInBytes - 1 - i;
293
0
      Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
294
0
    }
295
0
  }
296
1.17k
}
297
298
1.97k
bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
299
1.97k
  return false;
300
1.97k
}
301
302
bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
303
                                             uint64_t Value,
304
                                             const MCRelaxableFragment *DF,
305
0
                                             const MCAsmLayout &Layout, unsigned &KsError) const {
306
  // FIXME:  This isn't correct for AArch64. Just moving the "generic" logic
307
  // into the targets for now.
308
  //
309
  // Relax if the value is too big for a (signed) i8.
310
0
  return int64_t(Value) != int64_t(int8_t(Value));
311
0
}
312
313
void AArch64AsmBackend::relaxInstruction(const MCInst &Inst,
314
0
                                         MCInst &Res) const {
315
0
  llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented");
316
0
}
317
318
359
bool AArch64AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
319
  // If the count is not 4-byte aligned, we must be writing data into the text
320
  // section (otherwise we have unaligned instructions, and thus have far
321
  // bigger problems), so just write zeros instead.
322
359
  OW->WriteZeros(Count % 4);
323
324
  // We are properly aligned, so write NOPs as requested.
325
359
  Count /= 4;
326
484
  for (uint64_t i = 0; i != Count; ++i)
327
125
    OW->write32(0xd503201f);
328
359
  return true;
329
359
}
330
331
namespace {
332
333
namespace CU {
334
335
/// \brief Compact unwind encoding values.
336
enum CompactUnwindEncodings {
337
  /// \brief A "frameless" leaf function, where no non-volatile registers are
338
  /// saved. The return remains in LR throughout the function.
339
  UNWIND_AArch64_MODE_FRAMELESS = 0x02000000,
340
341
  /// \brief No compact unwind encoding available. Instead the low 23-bits of
342
  /// the compact unwind encoding is the offset of the DWARF FDE in the
343
  /// __eh_frame section. This mode is never used in object files. It is only
344
  /// generated by the linker in final linked images, which have only DWARF info
345
  /// for a function.
346
  UNWIND_AArch64_MODE_DWARF = 0x03000000,
347
348
  /// \brief This is a standard arm64 prologue where FP/LR are immediately
349
  /// pushed on the stack, then SP is copied to FP. If there are any
350
  /// non-volatile register saved, they are copied into the stack fame in pairs
351
  /// in a contiguous ranger right below the saved FP/LR pair. Any subset of the
352
  /// five X pairs and four D pairs can be saved, but the memory layout must be
353
  /// in register number order.
354
  UNWIND_AArch64_MODE_FRAME = 0x04000000,
355
356
  /// \brief Frame register pair encodings.
357
  UNWIND_AArch64_FRAME_X19_X20_PAIR = 0x00000001,
358
  UNWIND_AArch64_FRAME_X21_X22_PAIR = 0x00000002,
359
  UNWIND_AArch64_FRAME_X23_X24_PAIR = 0x00000004,
360
  UNWIND_AArch64_FRAME_X25_X26_PAIR = 0x00000008,
361
  UNWIND_AArch64_FRAME_X27_X28_PAIR = 0x00000010,
362
  UNWIND_AArch64_FRAME_D8_D9_PAIR = 0x00000100,
363
  UNWIND_AArch64_FRAME_D10_D11_PAIR = 0x00000200,
364
  UNWIND_AArch64_FRAME_D12_D13_PAIR = 0x00000400,
365
  UNWIND_AArch64_FRAME_D14_D15_PAIR = 0x00000800
366
};
367
368
} // end CU namespace
369
370
} // end anonymous namespace
371
372
namespace {
373
374
class ELFAArch64AsmBackend : public AArch64AsmBackend {
375
public:
376
  uint8_t OSABI;
377
378
  ELFAArch64AsmBackend(const Target &T, uint8_t OSABI, bool IsLittleEndian)
379
2.03k
    : AArch64AsmBackend(T, IsLittleEndian), OSABI(OSABI) {}
380
381
2.03k
  MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
382
2.03k
    return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian);
383
2.03k
  }
384
385
  void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
386
                         const MCFixup &Fixup, const MCFragment *DF,
387
                         const MCValue &Target, uint64_t &Value,
388
                         bool &IsResolved) override;
389
};
390
391
void ELFAArch64AsmBackend::processFixupValue(
392
    const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup,
393
    const MCFragment *DF, const MCValue &Target, uint64_t &Value,
394
1.77k
    bool &IsResolved) {
395
  // The ADRP instruction adds some multiple of 0x1000 to the current PC &
396
  // ~0xfff. This means that the required offset to reach a symbol can vary by
397
  // up to one step depending on where the ADRP is in memory. For example:
398
  //
399
  //     ADRP x0, there
400
  //  there:
401
  //
402
  // If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and
403
  // we'll need that as an offset. At any other address "there" will be in the
404
  // same page as the ADRP and the instruction should encode 0x0. Assuming the
405
  // section isn't 0x1000-aligned, we therefore need to delegate this decision
406
  // to the linker -- a relocation!
407
1.77k
  if ((uint32_t)Fixup.getKind() == AArch64::fixup_aarch64_pcrel_adrp_imm21)
408
0
    IsResolved = false;
409
1.77k
}
410
411
}
412
413
MCAsmBackend *llvm_ks::createAArch64leAsmBackend(const Target &T,
414
                                              const MCRegisterInfo &MRI,
415
                                              const Triple &TheTriple,
416
2.03k
                                              StringRef CPU) {
417
2.03k
  assert(TheTriple.isOSBinFormatELF() && "Expect either MachO or ELF target");
418
0
  uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
419
2.03k
  return new ELFAArch64AsmBackend(T, OSABI, /*IsLittleEndian=*/true);
420
2.03k
}
421
422
MCAsmBackend *llvm_ks::createAArch64beAsmBackend(const Target &T,
423
                                              const MCRegisterInfo &MRI,
424
                                              const Triple &TheTriple,
425
0
                                              StringRef CPU) {
426
0
  assert(TheTriple.isOSBinFormatELF() &&
427
0
         "Big endian is only supported for ELF targets!");
428
0
  uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
429
0
  return new ELFAArch64AsmBackend(T, OSABI,
430
0
                                  /*IsLittleEndian=*/false);
431
0
}