• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nickg / nvc / 9488083199

12 Jun 2024 06:42PM UTC coverage: 91.542% (-0.2%) from 91.777%
9488083199

push

github

nickg
Bump OS versions used in GitHub Actions

56705 of 61944 relevant lines covered (91.54%)

666304.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.29
/src/jit/jit-code.c
1
//
2
//  Copyright (C) 2022-2024  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "cpustate.h"
20
#include "debug.h"
21
#include "hash.h"
22
#include "ident.h"
23
#include "jit/jit-priv.h"
24
#include "option.h"
25
#include "thread.h"
26

27
#include <assert.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <stdio.h>
31
#include <unistd.h>
32
#include <inttypes.h>
33

34
#if defined __MINGW32__
35
#include <winnt.h>
36
#elif defined __APPLE__
37
#include <mach-o/loader.h>
38
#include <mach-o/reloc.h>
39
#include <mach-o/nlist.h>
40
#include <mach-o/stab.h>
41
#include <mach-o/arm64/reloc.h>
42
#include <mach-o/x86_64/reloc.h>
43
#else
44
#include <elf.h>
45
#endif
46

47
#ifdef HAVE_CAPSTONE
48
#include <capstone.h>
49
#endif
50

51
#ifndef R_AARCH64_MOVW_UABS_G0_NC
52
#define R_AARCH64_MOVW_UABS_G0_NC 264
53
#endif
54

55
#ifndef R_AARCH64_MOVW_UABS_G1_NC
56
#define R_AARCH64_MOVW_UABS_G1_NC 266
57
#endif
58

59
#ifndef R_AARCH64_MOVW_UABS_G2_NC
60
#define R_AARCH64_MOVW_UABS_G2_NC 268
61
#endif
62

63
#ifndef R_AARCH64_MOVW_UABS_G3
64
#define R_AARCH64_MOVW_UABS_G3 269
65
#endif
66

67
#ifndef SHT_X86_64_UNWIND
68
#define SHT_X86_64_UNWIND 0x70000001
69
#endif
70

71
#define CODE_PAGE_ALIGN   4096
72
#define CODE_PAGE_SIZE    0x400000
73
#define THREAD_CACHE_SIZE 0x10000
74
#define CODE_BLOB_ALIGN   256
75
#define MIN_BLOB_SIZE     0x4000
76

77
#define __IMM64(x) __IMM32(x), __IMM32((x) >> 32)
78
#define __IMM32(x) __IMM16(x), __IMM16((x) >> 16)
79
#define __IMM16(x) (x) & 0xff, ((x) >> 8) & 0xff
80

81
STATIC_ASSERT(MIN_BLOB_SIZE <= THREAD_CACHE_SIZE);
82
STATIC_ASSERT(MIN_BLOB_SIZE % CODE_BLOB_ALIGN == 0);
83
STATIC_ASSERT(CODE_PAGE_SIZE % THREAD_CACHE_SIZE == 0);
84

85
typedef struct _code_page code_page_t;
86

87
typedef struct {
88
   uintptr_t  addr;
89
   char      *text;
90
} code_comment_t;
91

92
typedef struct {
93
   unsigned        count;
94
   unsigned        max;
95
   code_comment_t *comments;
96
} code_debug_t;
97

98
typedef struct _code_span {
99
   code_cache_t *owner;
100
   code_span_t  *next;
101
   ident_t       name;
102
   uint8_t      *base;
103
   void         *entry;
104
   size_t        size;
105
#ifdef DEBUG
106
   code_debug_t  debug;
107
#endif
108
} code_span_t;
109

110
typedef struct _patch_list {
111
   patch_list_t    *next;
112
   uint8_t         *wptr;
113
   jit_label_t      label;
114
   code_patch_fn_t  fn;
115
} patch_list_t;
116

117
typedef struct _code_page {
118
   code_cache_t *owner;
119
   code_page_t  *next;
120
   uint8_t      *mem;
121
} code_page_t;
122

123
typedef struct _code_cache {
124
   nvc_lock_t   lock;
125
   code_page_t *pages;
126
   code_span_t *spans;
127
   code_span_t *freelist[MAX_THREADS];
128
   code_span_t *globalfree;
129
   FILE        *perfmap;
130
#ifdef HAVE_CAPSTONE
131
   csh          capstone;
132
#endif
133
#ifdef DEBUG
134
   size_t       used;
135
#endif
136
} code_cache_t;
137

138
static void code_disassemble(code_span_t *span, uintptr_t mark,
139
                             struct cpu_state *cpu);
140

141
static void code_cache_unwinder(uintptr_t addr, debug_frame_t *frame,
×
142
                                void *context)
143
{
144
   code_cache_t *code = context;
×
145

146
   const uint8_t *pc = (uint8_t *)addr;
×
147
   for (code_span_t *span = code->spans; span; span = span->next) {
×
148
      if (pc >= span->base && pc < span->base + span->size) {
×
149
         frame->kind = FRAME_VHDL;
×
150
         frame->disp = pc - span->base;
×
151
         frame->symbol = istr(span->name);
×
152
      }
153
   }
154
}
×
155

156
static void code_fault_handler(int sig, void *addr, struct cpu_state *cpu,
×
157
                               void *context)
158
{
159
   code_page_t *page = context;
×
160

161
   const uint8_t *pc = (uint8_t *)cpu->pc;
×
162
   if (pc < page->mem || pc > page->mem + CODE_PAGE_SIZE)
×
163
      return;
164

165
   uintptr_t mark = cpu->pc;
×
166
#ifndef __MINGW32__
167
   if (sig == SIGTRAP)
×
168
      mark--;   // Point to faulting instruction
×
169
#endif
170

171
   for (code_span_t *span = page->owner->spans; span; span = span->next) {
×
172
      if (pc >= span->base && pc < span->base + span->size && span->name)
×
173
         code_disassemble(span, mark, cpu);
×
174
   }
175
}
176

177
#ifdef DEBUG
178
static bool code_cache_contains(code_cache_t *code, uint8_t *base, size_t size)
8,505✔
179
{
180
   assert_lock_held(&code->lock);
8,505✔
181

182
   for (code_page_t *p = code->pages; p; p = p->next) {
8,505✔
183
      if (base >= p->mem && base + size <= p->mem + CODE_PAGE_SIZE)
8,505✔
184
         return true;
185
   }
186

187
   return false;
188
}
189
#endif
190

191
static code_span_t *code_span_new(code_cache_t *code, ident_t name,
8,505✔
192
                                  uint8_t *base, size_t size)
193
{
194
   SCOPED_LOCK(code->lock);
8,505✔
195

196
   assert(code_cache_contains(code, base, size));
8,505✔
197

198
   code_span_t *span = xcalloc(sizeof(code_span_t));
8,505✔
199
   span->name  = name;
8,505✔
200
   span->next  = code->spans;
8,505✔
201
   span->base  = base;
8,505✔
202
   span->entry = base;
8,505✔
203
   span->size  = size;
8,505✔
204
   span->owner = code;
8,505✔
205

206
   code->spans = span;
8,505✔
207
   return span;
8,505✔
208
}
209

210
static void code_page_new(code_cache_t *code)
3,184✔
211
{
212
   assert_lock_held(&code->lock);
3,184✔
213

214
   code_page_t *page = xcalloc(sizeof(code_page_t));
3,184✔
215
   page->owner = code;
3,184✔
216
   page->next  = code->pages;
3,184✔
217
   page->mem   = map_jit_pages(CODE_PAGE_ALIGN, CODE_PAGE_SIZE);
3,184✔
218

219
   add_fault_handler(code_fault_handler, page);
3,184✔
220
   debug_add_unwinder(page->mem, CODE_PAGE_SIZE, code_cache_unwinder, code);
3,184✔
221

222
   code->pages = page;
3,184✔
223

224
   code_span_t *span = xcalloc(sizeof(code_span_t));
3,184✔
225
   span->next  = code->spans;
3,184✔
226
   span->base  = page->mem;
3,184✔
227
   span->size  = CODE_PAGE_SIZE;
3,184✔
228
   span->owner = code;
3,184✔
229

230
   code->globalfree = code->spans = span;
3,184✔
231
}
3,184✔
232

233
code_cache_t *code_cache_new(void)
3,177✔
234
{
235
   code_cache_t *code = xcalloc(sizeof(code_cache_t));
3,177✔
236

237
   {
238
      SCOPED_LOCK(code->lock);
6,354✔
239
      code_page_new(code);
3,177✔
240
   }
241

242
#ifdef HAVE_CAPSTONE
243
#if defined ARCH_X86_64
244
   if (cs_open(CS_ARCH_X86, CS_MODE_64, &(code->capstone)) != CS_ERR_OK)
245
      fatal_trace("failed to init capstone for x86_64");
246
#elif defined ARCH_ARM64
247
   if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &(code->capstone)) != CS_ERR_OK)
248
      fatal_trace("failed to init capstone for Arm64");
249
#else
250
#error Cannot configure capstone for this architecture
251
#endif
252

253
   if (cs_option(code->capstone, CS_OPT_DETAIL, 1) != CS_ERR_OK)
254
      fatal_trace("failed to set capstone detailed mode");
255
#endif
256

257
   return code;
3,177✔
258
}
259

260
void code_cache_free(code_cache_t *code)
3,175✔
261
{
262
   for (code_page_t *it = code->pages, *tmp; it; it = tmp) {
6,357✔
263
      debug_remove_unwinder(it->mem);
3,182✔
264
      remove_fault_handler(code_fault_handler, it);
3,182✔
265

266
      nvc_munmap(it->mem, CODE_PAGE_SIZE);
3,182✔
267

268
      tmp = it->next;
3,182✔
269
      free(it);
3,182✔
270
   }
271

272
   for (code_span_t *it = code->spans, *tmp; it; it = tmp) {
14,862✔
273
      tmp = it->next;
11,687✔
274
      free(it);
11,687✔
275
   }
276

277
#ifdef HAVE_CAPSTONE
278
   cs_close(&(code->capstone));
279
#endif
280

281
#ifdef DEBUG
282
   if (code->used > 0)
3,175✔
283
      debugf("JIT code footprint: %zu bytes", code->used);
1,118✔
284
#endif
285

286
   free(code);
3,175✔
287
}
3,175✔
288

289
#ifdef HAVE_CAPSTONE
290
static int code_print_spaces(int col, int tab)
291
{
292
   for (; col < tab; col++)
293
      fputc(' ', stdout);
294
   return col;
295
}
296
#endif
297

298
static void code_disassemble(code_span_t *span, uintptr_t mark,
×
299
                             struct cpu_state *cpu)
300
{
301
   SCOPED_LOCK(span->owner->lock);
×
302

303
   printf("--");
×
304

305
   const int namelen = ident_len(span->name);
×
306
   for (int i = 0; i < 72 - namelen; i++)
×
307
      fputc('-', stdout);
×
308

309
   printf(" %s ----\n", istr(span->name));
×
310

311
#ifdef HAVE_CAPSTONE
312
   cs_insn *insn = cs_malloc(span->owner->capstone);
313

314
#ifdef DEBUG
315
   code_comment_t *comment = span->debug.comments;
316
#endif
317

318
   const uint8_t *const eptr = span->base + span->size;
319
   for (const uint8_t *ptr = span->base; ptr < eptr; ) {
320
      uint64_t address = (uint64_t)ptr;
321

322
#ifdef DEBUG
323
      for (; comment < span->debug.comments + span->debug.count
324
              && comment->addr <= address; comment++)
325
         printf("%30s;; %s\n", "", comment->text);
326
#endif
327

328
      int zeros = 0;
329
      for (const uint8_t *zp = ptr; zp < eptr && *zp == 0; zp++, zeros++);
330

331
      if (zeros > 8 || zeros == eptr - ptr) {
332
         printf("%30s;; skipping %d zero bytes\n", "", zeros);
333
         ptr += zeros;
334
         continue;
335
      }
336

337
      size_t size = eptr - ptr;
338
      int col = 0;
339
      if (cs_disasm_iter(span->owner->capstone, &ptr, &size, &address, insn)) {
340
         char hex1[33], *p = hex1;
341
         for (size_t k = 0; k < insn->size; k++)
342
            p += checked_sprintf(p, hex1 + sizeof(hex1) - p, "%02x",
343
                                 insn->bytes[k]);
344

345
         col = printf("%-12" PRIx64 " %-16.16s %s %s", insn->address,
346
                          hex1, insn->mnemonic, insn->op_str);
347

348
#ifdef ARCH_X86_64
349
         if (strcmp(insn->mnemonic, "movabs") == 0) {
350
            const cs_x86_op *src = &(insn->detail->x86.operands[1]);
351
            if (src->type == X86_OP_IMM) {
352
               const char *sym = debug_symbol_name((void *)src->imm);
353
               if (sym != NULL) {
354
                  col = code_print_spaces(col, 60);
355
                  col += printf(" ; %s", sym);
356
               }
357
            }
358
         }
359
#endif
360

361
         if (strlen(hex1) > 16)
362
            col = printf("\n%15s -%-16s", "", hex1 + 16) - 1;
363
      }
364
      else {
365
#ifdef ARCH_ARM64
366
         col = printf("%-12" PRIx64 " %-16.08x %s 0x%08x", (uint64_t)ptr,
367
                      *(uint32_t *)ptr, ".word", *(uint32_t *)ptr);
368
         ptr += 4;
369
#else
370
         col = printf("%-12" PRIx64 " %-16.02x %s 0x%02x", (uint64_t)ptr,
371
                      *ptr, ".byte", *ptr);
372
         ptr++;
373
#endif
374
      }
375

376
      if (mark != 0 && (ptr >= eptr || address > mark)) {
377
         col = code_print_spaces(col, 66);
378
         printf("<=============\n");
379
         if (cpu != NULL) {
380
#ifdef ARCH_X86_64
381
            const char *names[] = {
382
               "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
383
               "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"
384
            };
385
            for (int i = 0; i < ARRAY_LEN(names); i++)
386
               printf("\t%s\t%"PRIxPTR"\n", names[i], cpu->regs[i]);
387
#else
388
            for (int i = 0; i < 32; i++)
389
               printf("\tR%d\t%"PRIxPTR"\n", i, cpu->regs[i]);
390
#endif
391
         }
392
         mark = 0;
393
      }
394
      else
395
         printf("\n");
396
   }
397

398
   cs_free(insn, 1);
399
#else
400
   jit_hexdump(span->base, span->size, 16, (void *)mark, "");
×
401
#endif
402

403
   for (int i = 0; i < 80; i++)
×
404
      fputc('-', stdout);
×
405
   printf("\n");
×
406
   fflush(stdout);
×
407
}
×
408

409
static void code_write_perf_map(code_span_t *span)
×
410
{
411
   SCOPED_LOCK(span->owner->lock);
×
412

413
   if (span->owner->perfmap == NULL) {
×
414
      char *fname LOCAL = xasprintf("/tmp/perf-%d.map", getpid());
×
415
      if ((span->owner->perfmap = fopen(fname, "w")) == NULL) {
×
416
         warnf("cannot create %s: %s", fname, last_os_error());
×
417
         opt_set_int(OPT_PERF_MAP, 0);
×
418
         return;
×
419
      }
420
      else
421
         debugf("writing perf map to %s", fname);
×
422
   }
423

424
   fprintf(span->owner->perfmap, "%p 0x%zx %s\n", span->base, span->size,
×
425
           istr(span->name));
426
   fflush(span->owner->perfmap);
×
427
}
428

429
code_blob_t *code_blob_new(code_cache_t *code, ident_t name, size_t hint)
7,384✔
430
{
431
   code_span_t **freeptr = &(code->freelist[thread_id()]);
7,384✔
432

433
   code_span_t *free = relaxed_load(freeptr);
7,384✔
434
   if (free == NULL) {
7,384✔
435
      free = code_span_new(code, NULL, code->pages->mem, 0);
1,121✔
436
      relaxed_store(freeptr, free);
1,121✔
437
   }
438

439
   const size_t reqsz = hint ?: MIN_BLOB_SIZE;
7,384✔
440

441
   if (free->size < reqsz) {
7,384✔
442
      SCOPED_LOCK(code->lock);
1,191✔
443

444
#ifdef DEBUG
445
      if (free->size > 0)
1,191✔
446
         debugf("thread %d needs new code cache from global free list "
24✔
447
                "(requested %zu bytes, wasted %zu bytes)",
448
                thread_id(), reqsz, free->size);
449
#endif
450

451
      const size_t chunksz = MAX(reqsz, THREAD_CACHE_SIZE);
1,191✔
452
      const size_t alignedsz = ALIGN_UP(chunksz, CODE_BLOB_ALIGN);
1,191✔
453

454
      if (alignedsz > code->globalfree->size) {
1,191✔
455
         DEBUG_ONLY(debugf("requesting new %d byte code page", CODE_PAGE_SIZE));
7✔
456
         code_page_new(code);
7✔
457
         assert(code->globalfree->size == CODE_PAGE_SIZE);
7✔
458
      }
459

460
      const size_t take = MIN(code->globalfree->size, alignedsz);
1,191✔
461

462
      free->size = take;
1,191✔
463
      free->base = code->globalfree->base;
1,191✔
464

465
      code->globalfree->base += take;
1,191✔
466
      code->globalfree->size -= take;
1,191✔
467
   }
468

469
   assert(reqsz <= free->size);
7,384✔
470
   assert(((uintptr_t)free->base & (CODE_BLOB_ALIGN - 1)) == 0);
7,384✔
471

472
   code_span_t *span = code_span_new(code, name, free->base, free->size);
7,384✔
473

474
   free->base += span->size;
7,384✔
475
   free->size -= span->size;
7,384✔
476

477
   code_blob_t *blob = xcalloc(sizeof(code_blob_t));
7,384✔
478
   blob->span = span;
7,384✔
479
   blob->wptr = span->base;
7,384✔
480

481
   thread_wx_mode(WX_WRITE);
7,384✔
482

483
   return blob;
7,384✔
484
}
485

486
void code_blob_finalise(code_blob_t *blob, jit_entry_fn_t *entry)
7,384✔
487
{
488
   code_span_t *span = blob->span;
7,384✔
489
   span->size = blob->wptr - span->base;
7,384✔
490

491
   code_span_t *freespan = relaxed_load(&(span->owner->freelist[thread_id()]));
7,384✔
492
   assert(freespan->size == 0);
7,384✔
493

494
   ihash_free(blob->labels);
7,384✔
495
   blob->labels = NULL;
7,384✔
496

497
   if (unlikely(blob->patches != NULL))
7,384✔
498
      fatal_trace("not all labels in %s were patched", istr(span->name));
×
499
   else if (unlikely(blob->overflow)) {
7,384✔
500
      // Return all the memory
501
      freespan->size = freespan->base - span->base;
1✔
502
      freespan->base = span->base;
1✔
503
      free(blob);
1✔
504
      return;
1✔
505
   }
506
   else if (span->size == 0)
7,383✔
507
      fatal_trace("code span %s is empty", istr(span->name));
×
508

509
   uint8_t *aligned = ALIGN_UP(blob->wptr, CODE_BLOB_ALIGN);
7,383✔
510
   freespan->size = freespan->base - aligned;
7,383✔
511
   freespan->base = aligned;
7,383✔
512

513
   if (opt_get_verbose(OPT_ASM_VERBOSE, istr(span->name))) {
7,383✔
514
      color_printf("\n$bold$$blue$");
×
515
      code_disassemble(span, 0, NULL);
×
516
      color_printf("$$\n");
×
517
   }
518

519
   __builtin___clear_cache((char *)span->base, (char *)blob->wptr);
7,383✔
520

521
   thread_wx_mode(WX_EXECUTE);
7,383✔
522

523
   store_release(entry, (jit_entry_fn_t)span->entry);
7,383✔
524

525
   DEBUG_ONLY(relaxed_add(&span->owner->used, span->size));
7,383✔
526
   free(blob);
7,383✔
527

528
   if (opt_get_int(OPT_PERF_MAP))
7,383✔
529
      code_write_perf_map(span);
×
530
}
531

532
__attribute__((cold, noinline))
533
static void code_blob_overflow(code_blob_t *blob)
1✔
534
{
535
   warnf("JIT code buffer for %s too small", istr(blob->span->name));
1✔
536
   for (patch_list_t *it = blob->patches, *tmp; it; it = tmp) {
1✔
537
      tmp = it->next;
×
538
      free(it);
×
539
   }
540
   blob->patches = NULL;
1✔
541
   blob->overflow = true;
1✔
542
}
1✔
543

544
void code_blob_emit(code_blob_t *blob, const uint8_t *bytes, size_t len)
16,977✔
545
{
546
   if (unlikely(blob->overflow))
16,977✔
547
      return;
548
   else if (unlikely(blob->wptr + len > blob->span->base + blob->span->size)) {
16,977✔
549
      code_blob_overflow(blob);
1✔
550
      return;
1✔
551
   }
552

553
   if (len < 8) {
16,976✔
554
      for (size_t i = 0; i < len; i++)
21,727✔
555
         *(blob->wptr++) = bytes[i];
12,535✔
556
   }
557
   else {
558
      memcpy(blob->wptr, bytes, len);
7,784✔
559
      blob->wptr += len;
7,784✔
560
   }
561
}
562

563
void code_blob_align(code_blob_t *blob, unsigned align)
7,612✔
564
{
565
#ifdef ARCH_X86_64
566
   const uint8_t pad[] = { 0x90 };
7,612✔
567
#else
568
   const uint8_t pad[] = { 0x00 };
569
#endif
570

571
   assert(is_power_of_2(align));
7,612✔
572
   assert(align % ARRAY_LEN(pad) == 0);
573

574
   while (((uintptr_t)blob->wptr & (align - 1)) && !blob->overflow)
7,909✔
575
      code_blob_emit(blob, pad, ARRAY_LEN(pad));
297✔
576
}
7,612✔
577

578
void code_blob_mark(code_blob_t *blob, jit_label_t label)
70✔
579
{
580
   if (unlikely(blob->overflow))
70✔
581
      return;
582
   else if (blob->labels == NULL)
70✔
583
      blob->labels = ihash_new(256);
65✔
584

585
   ihash_put(blob->labels, label, blob->wptr);
70✔
586

587
   for (patch_list_t **p = &(blob->patches); *p; ) {
87✔
588
      if ((*p)->label == label) {
17✔
589
         patch_list_t *next = (*p)->next;
7✔
590
         (*(*p)->fn)(blob, label, (*p)->wptr, blob->wptr);
7✔
591
         free(*p);
7✔
592
         *p = next;
7✔
593
      }
594
      else
595
         p = &((*p)->next);
10✔
596
   }
597
}
598

599
void code_blob_patch(code_blob_t *blob, jit_label_t label, code_patch_fn_t fn)
8✔
600
{
601
   void *ptr = NULL;
8✔
602
   if (unlikely(blob->overflow))
8✔
603
      return;
604
   else if (blob->labels != NULL && (ptr = ihash_get(blob->labels, label)))
8✔
605
      (*fn)(blob, label, blob->wptr, ptr);
1✔
606
   else {
607
      patch_list_t *new = xmalloc(sizeof(patch_list_t));
7✔
608
      new->next  = blob->patches;
7✔
609
      new->fn    = fn;
7✔
610
      new->label = label;
7✔
611
      new->wptr  = blob->wptr;
7✔
612

613
      blob->patches = new;
7✔
614
   }
615
}
616

617
#ifdef DEBUG
618
static void code_blob_print_value(text_buf_t *tb, jit_value_t value)
387✔
619
{
620
   switch (value.kind) {
387✔
621
   case JIT_VALUE_REG:
160✔
622
      tb_printf(tb, "R%d", value.reg);
160✔
623
      break;
160✔
624
   case JIT_VALUE_INT64:
200✔
625
      if (value.int64 < 4096)
200✔
626
         tb_printf(tb, "#%"PRIi64, value.int64);
197✔
627
      else
628
         tb_printf(tb, "#0x%"PRIx64, value.int64);
3✔
629
      break;
630
   case JIT_VALUE_DOUBLE:
1✔
631
      tb_printf(tb, "%%%g", value.dval);
1✔
632
      break;
1✔
633
   case JIT_ADDR_CPOOL:
×
634
      tb_printf(tb, "[CP+%"PRIi64"]", value.int64);
×
635
      break;
×
636
   case JIT_ADDR_REG:
19✔
637
      tb_printf(tb, "[R%d", value.reg);
19✔
638
      if (value.disp != 0)
19✔
639
         tb_printf(tb, "+%d", value.disp);
1✔
640
      tb_cat(tb, "]");
19✔
641
      break;
19✔
642
   case JIT_ADDR_ABS:
×
643
      tb_printf(tb, "[#%016"PRIx64"]", value.int64);
×
644
      break;
×
645
   case JIT_ADDR_COVER:
×
646
      tb_printf(tb, "@%"PRIi64, value.int64);
×
647
      break;
×
648
   case JIT_VALUE_LABEL:
5✔
649
      tb_printf(tb, "%d", value.label);
5✔
650
      break;
5✔
651
   case JIT_VALUE_HANDLE:
2✔
652
      tb_printf(tb, "<%d>", value.handle);
2✔
653
      break;
2✔
654
   case JIT_VALUE_EXIT:
×
655
      tb_printf(tb, "%s", jit_exit_name(value.exit));
×
656
      break;
×
657
   case JIT_VALUE_LOC:
×
658
      tb_printf(tb, "<%s:%d>", loc_file_str(&value.loc), value.loc.first_line);
×
659
      break;
×
660
   case JIT_VALUE_LOCUS:
×
661
      tb_printf(tb, "%s%+d", istr(value.ident), value.disp);
×
662
      break;
×
663
   case JIT_VALUE_VPOS:
×
664
      tb_printf(tb, "%u:%u", value.vpos.block, value.vpos.op);
×
665
      break;
×
666
   default:
×
667
      tb_cat(tb, "???");
×
668
   }
669
}
387✔
670

671
static void code_blob_add_comment(code_blob_t *blob, char *text)
344✔
672
{
673
   code_debug_t *dbg = &(blob->span->debug);
344✔
674

675
   if (dbg->count == dbg->max) {
344✔
676
      dbg->max = MAX(128, dbg->max * 2);
65✔
677
      dbg->comments = xrealloc_array(dbg->comments, dbg->max,
65✔
678
                                     sizeof(code_comment_t));
679
   }
680

681
   dbg->comments[dbg->count].addr = (uintptr_t)blob->wptr;
344✔
682
   dbg->comments[dbg->count].text = text;
344✔
683
   dbg->count++;
344✔
684
}
344✔
685

686
void code_blob_print_ir(code_blob_t *blob, jit_ir_t *ir)
344✔
687
{
688
   LOCAL_TEXT_BUF tb = tb_new();
688✔
689
   tb_printf(tb, "%s%s", jit_op_name(ir->op), jit_cc_name(ir->cc));
344✔
690

691
   if (ir->size != JIT_SZ_UNSPEC)
344✔
692
      tb_printf(tb, ".%d", 1 << (3 + ir->size));
35✔
693

694
   tb_printf(tb, "%*.s", (int)MAX(0, 10 - tb_len(tb)), "");
344✔
695

696
   if (ir->result != JIT_REG_INVALID)
344✔
697
      tb_printf(tb, "R%d", ir->result);
201✔
698

699
   if (ir->arg1.kind != JIT_VALUE_INVALID) {
344✔
700
      if (ir->result != JIT_REG_INVALID)
260✔
701
         tb_cat(tb, ", ");
185✔
702
      code_blob_print_value(tb, ir->arg1);
260✔
703
   }
704

705
   if (ir->arg2.kind != JIT_VALUE_INVALID) {
344✔
706
      tb_cat(tb, ", ");
127✔
707
      code_blob_print_value(tb, ir->arg2);
127✔
708
   }
709

710
   code_blob_add_comment(blob, tb_claim(tb));
344✔
711
}
344✔
712

713
void code_blob_printf(code_blob_t *blob, const char *fmt, ...)
×
714
{
715
   code_debug_t *dbg = &(blob->span->debug);
×
716

717
   if (dbg->count == dbg->max) {
×
718
      dbg->max = MAX(128, dbg->max * 2);
×
719
      dbg->comments = xrealloc_array(dbg->comments, dbg->max,
×
720
                                     sizeof(code_comment_t));
721
   }
722

723
   va_list ap;
×
724
   va_start(ap, fmt);
×
725

726
   char *text = xvasprintf(fmt, ap);
×
727
   code_blob_add_comment(blob, text);
×
728

729
   va_end(ap);
×
730
}
×
731
#endif   // DEBUG
732

733
#ifdef ARCH_ARM64
734
static void *arm64_emit_trampoline(code_blob_t *blob, uintptr_t dest)
735
{
736
   const uint8_t veneer[] = {
737
      0x50, 0x00, 0x00, 0x58,   // LDR X16, [PC+8]
738
      0x00, 0x02, 0x1f, 0xd6,   // BR X16
739
      __IMM64(dest)
740
   };
741

742
   void *prev = memmem(blob->span->base, blob->span->size,
743
                       veneer, ARRAY_LEN(veneer));
744
   if (prev != NULL)
745
      return prev;
746
   else {
747
      void *addr = blob->wptr;
748
      code_blob_emit(blob, veneer, ARRAY_LEN(veneer));
749
      return addr;
750
   }
751
}
752
#else
753
#define arm64_emit_trampoline(blob, dest) NULL
754
#endif
755

756
#if defined __MINGW32__
757
static void code_load_pe(code_blob_t *blob, const void *data, size_t size)
758
{
759
   const IMAGE_FILE_HEADER *imghdr = data;
760

761
   if (imghdr->Machine != IMAGE_FILE_MACHINE_AMD64)
762
      fatal_trace("unknown target machine %x", imghdr->Machine);
763

764
   const IMAGE_SYMBOL *symtab = data + imghdr->PointerToSymbolTable;
765
   const char *strtab = data + imghdr->PointerToSymbolTable
766
      + imghdr->NumberOfSymbols * sizeof(IMAGE_SYMBOL);
767

768
   const IMAGE_SECTION_HEADER *sections =
769
      data + IMAGE_SIZEOF_FILE_HEADER + imghdr->SizeOfOptionalHeader;
770

771
   void **load_addr LOCAL =
772
      xmalloc_array(imghdr->NumberOfSections, sizeof(void *));
773

774
   for (int i = 0; i < imghdr->NumberOfSections; i++) {
775
      if ((sections[i].Characteristics & IMAGE_SCN_CNT_CODE)
776
          || (sections[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)) {
777
         const int align = sections[i].Characteristics & IMAGE_SCN_ALIGN_MASK;
778
         code_blob_align(blob, 1 << ((align >> 20) - 1));
779
         load_addr[i] = blob->wptr;
780
         code_blob_emit(blob, data + sections[i].PointerToRawData,
781
                        sections[i].SizeOfRawData);
782
      }
783
      else if ((sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
784
               && sections[i].Misc.VirtualSize > 0)
785
         fatal_trace("non-empty BSS not supported");
786
   }
787

788
   if (blob->overflow)
789
      return;   // Relocations might point outside of code span
790

791
   for (int i = 0; i < imghdr->NumberOfSections; i++) {
792
      const IMAGE_RELOCATION *relocs = data + sections[i].PointerToRelocations;
793
      for (int j = 0; j < sections[i].NumberOfRelocations; j++) {
794
         const char *name = NULL;
795
         char tmp[9];
796

797
         assert(relocs[j].SymbolTableIndex < imghdr->NumberOfSymbols);
798
         const IMAGE_SYMBOL *sym = symtab + relocs[j].SymbolTableIndex;
799

800
         if (sym->N.Name.Short) {
801
            memcpy(tmp, sym->N.ShortName, 8);
802
            tmp[8] = '\0';
803
            name = tmp;
804
         }
805
         else
806
            name = strtab + sym->N.Name.Long;
807

808
         void *ptr = NULL;
809
         if (sym->SectionNumber > 0) {
810
            assert(sym->SectionNumber - 1 < imghdr->NumberOfSections);
811
            ptr = load_addr[sym->SectionNumber - 1] + sym->Value;
812
         }
813
#ifdef ARCH_X86_64
814
         else if (strcmp(name, "___chkstk_ms") == 0) {
815
            extern void ___chkstk_ms(void);
816
            ptr = &___chkstk_ms;
817
         }
818
#endif
819
         else
820
            ptr = ffi_find_symbol(NULL, name);
821

822
         if (ptr == NULL && icmp(blob->span->name, name))
823
            ptr = blob->span->base;
824

825
         if (ptr == NULL)
826
            fatal_trace("failed to resolve symbol %s", name);
827

828
         void *patch = load_addr[i] + relocs[j].VirtualAddress;
829
         assert((uint8_t *)patch >= blob->span->base);
830
         assert((uint8_t *)patch < blob->span->base + blob->span->size);
831

832
         switch (relocs[j].Type) {
833
#ifdef ARCH_X86_64
834
         case IMAGE_REL_AMD64_ADDR64:
835
            *(uint64_t *)patch += (uint64_t)ptr;
836
            break;
837
         case IMAGE_REL_AMD64_ADDR32NB:
838
            *(uint32_t *)patch += (uint32_t)(ptr - (void *)blob->span->base);
839
            break;
840
#endif
841
         default:
842
            blob->span->size = blob->wptr - blob->span->base;
843
            code_disassemble(blob->span, (uintptr_t)patch, NULL);
844
            fatal_trace("cannot handle relocation type %d for symbol %s",
845
                        relocs[j].Type, name);
846
         }
847
      }
848

849
      if (strncmp((const char *)sections[i].Name, ".pdata",
850
                  IMAGE_SIZEOF_SHORT_NAME) == 0) {
851
         assert(sections[i].SizeOfRawData % sizeof(RUNTIME_FUNCTION) == 0);
852
         const int count = sections[i].SizeOfRawData / sizeof(RUNTIME_FUNCTION);
853
         const DWORD64 base = (DWORD64)blob->span->base;
854

855
         // TODO: we should also call RtlDeleteFunctionTable at some point
856
         if (!RtlAddFunctionTable(load_addr[i], count, base))
857
            fatal_trace("RtlAddFunctionTable failed: %s", last_os_error());
858
      }
859
   }
860

861
   for (int i = 0; i < imghdr->NumberOfSymbols; i++) {
862
      const IMAGE_SYMBOL *sym = &(symtab[i]);
863

864
      if (sym->SectionNumber == 0 || sym->N.Name.Short)
865
         continue;
866
      else if ((sym->Type >> 4) != IMAGE_SYM_DTYPE_FUNCTION)
867
         continue;
868
      else if (icmp(blob->span->name, strtab + sym->N.Name.Long)) {
869
         blob->span->entry = load_addr[sym->SectionNumber - 1] + sym->Value;
870
         break;
871
      }
872
   }
873
}
874
#elif defined __APPLE__
875
static void code_load_macho(code_blob_t *blob, const void *data, size_t size)
876
{
877
   const void *rptr = data;
878

879
   const struct mach_header_64 *fhdr = rptr;
880
   rptr += sizeof(struct mach_header_64);
881

882
   if (fhdr->magic != MH_MAGIC_64)
883
      fatal_trace("bad Mach-O magic %x", fhdr->magic);
884

885
   const struct segment_command_64 *seg = NULL;
886
   const struct symtab_command *symtab = NULL;
887

888
   void **load_addr LOCAL = NULL;
889

890
   for (int i = 0; i < fhdr->ncmds; i++) {
891
      const struct load_command *load = rptr;
892
      switch (load->cmd) {
893
      case LC_SEGMENT_64:
894
         {
895
            seg = rptr;
896
            load_addr = xmalloc_array(seg->nsects, sizeof(void *));
897

898
            for (int j = 0; j < seg->nsects; j++) {
899
               const struct section_64 *sec =
900
                  (void *)seg + sizeof(struct segment_command_64)
901
                  + j * sizeof(struct section_64);
902
               code_blob_align(blob, 1 << sec->align);
903
               load_addr[j] = blob->wptr;
904
               code_blob_emit(blob, data + sec->offset, sec->size);
905
            }
906
         }
907
         break;
908
      case LC_SYMTAB:
909
         symtab = rptr;
910
         assert(symtab->cmdsize == sizeof(struct symtab_command));
911
         break;
912
      case LC_DATA_IN_CODE:
913
      case LC_LINKER_OPTIMIZATION_HINT:
914
      case LC_BUILD_VERSION:
915
      case LC_DYSYMTAB:
916
         break;
917
      default:
918
         warnf("unrecognised load command 0x%0x", load->cmd);
919
      }
920

921
      rptr += load->cmdsize;
922
   }
923
   assert(rptr == data + sizeof(struct mach_header_64) + fhdr->sizeofcmds);
924

925
   if (blob->overflow)
926
      return;   // Relocations might point outside of code span
927

928
   assert(seg != NULL);
929
   assert(symtab != NULL);
930

931
   for (int i = 0; i < seg->nsects; i++) {
932
      const struct section_64 *sec =
933
         (void *)seg + sizeof(struct segment_command_64)
934
         + i * sizeof(struct section_64);
935

936
      uint32_t addend = 0;
937
      for (int j = 0; j < sec->nreloc; j++) {
938
         const struct relocation_info *rel =
939
            data + sec->reloff + j * sizeof(struct relocation_info);
940
         const char *name = NULL;
941
         void *ptr = NULL;
942
         if (rel->r_extern) {
943
            assert(rel->r_symbolnum < symtab->nsyms);
944
            const struct nlist_64 *nl = data + symtab->symoff
945
               + rel->r_symbolnum * sizeof(struct nlist_64);
946
            name = data + symtab->stroff + nl->n_un.n_strx;
947

948
            if (nl->n_type & N_EXT) {
949
               if (icmp(blob->span->name, name + 1))
950
                  ptr = blob->span->base;
951
               else if ((ptr = ffi_find_symbol(NULL, name + 1)) == NULL)
952
                  fatal_trace("failed to resolve symbol %s", name + 1);
953
            }
954
            else if (nl->n_sect != NO_SECT)
955
               ptr = blob->span->base + nl->n_value;
956
         }
957
         else
958
            ptr = blob->span->base;
959

960
         ptr += addend;
961
         addend = 0;
962

963
         void *patch = load_addr[i] + rel->r_address;
964
         assert((uint8_t *)patch >= blob->span->base);
965
         assert((uint8_t *)patch < blob->span->base + blob->span->size);
966

967
         switch (rel->r_type) {
968
#ifdef ARCH_ARM64
969
         case ARM64_RELOC_UNSIGNED:
970
            assert(rel->r_length == 3);
971
            *(void **)patch = ptr;
972
            break;
973
         case ARM64_RELOC_SUBTRACTOR:
974
            break;   // What is this?
975
         case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
976
         case ARM64_RELOC_PAGEOFF12:
977
            switch ((*(uint32_t *)patch >> 23) & 0x7f) {
978
            case 0b1111010:   // LDR (immediate, SIMD&FP)
979
            case 0b1110010:   // LDR (immediate)
980
               assert(*(uint32_t *)patch & (1 << 30));  // Quadword
981
               assert(((uintptr_t)ptr & 7) == 0);
982
               *(uint32_t *)patch |= (((uintptr_t)ptr & 0xfff) >> 3) << 10;
983
               break;
984
            case 0b0100010:   // ADD (immediate)
985
               *(uint32_t *)patch |= ((uintptr_t)ptr & 0xfff) << 10;
986
               break;
987
            default:
988
               blob->span->size = blob->wptr - blob->span->base;
989
               code_disassemble(blob->span, (uintptr_t)patch, NULL);
990
               fatal_trace("cannot patch instruction");
991
            }
992
            break;
993
         case ARM64_RELOC_GOT_LOAD_PAGE21:
994
         case ARM64_RELOC_PAGE21:
995
            {
996
               const intptr_t dst_page = (intptr_t)ptr & ~UINT64_C(0xfff);
997
               const intptr_t src_page = (intptr_t)patch & ~UINT64_C(0xfff);
998
               const intptr_t upper21 = (dst_page - src_page) >> 12;
999
               *(uint32_t *)patch |= (upper21 & 3) << 29;
1000
               *(uint32_t *)patch |= ((upper21 >> 2) & 0x7ffff) << 5;
1001
            }
1002
            break;
1003
         case ARM64_RELOC_BRANCH26:
1004
            {
1005
               void *veneer = arm64_emit_trampoline(blob, (uintptr_t)ptr);
1006
               const ptrdiff_t pcrel = (veneer - patch) >> 2;
1007
               *(uint32_t *)patch &= ~0x3ffffff;
1008
               *(uint32_t *)patch |= pcrel & 0x3ffffff;
1009
            }
1010
            break;
1011
         case ARM64_RELOC_ADDEND:
1012
            addend = rel->r_symbolnum;
1013
            break;
1014
#elif defined ARCH_X86_64
1015
         case X86_64_RELOC_UNSIGNED:
1016
            *(uint64_t *)patch += (uint64_t)ptr;
1017
            break;
1018
         case X86_64_RELOC_BRANCH:
1019
            *(uint32_t *)patch += (uint32_t)(ptr - patch - 4);
1020
            break;
1021
#endif
1022
         default:
1023
            blob->span->size = blob->wptr - blob->span->base;
1024
            code_disassemble(blob->span, (uintptr_t)patch, NULL);
1025
            fatal_trace("cannot handle relocation type %d for symbol %s",
1026
                        rel->r_type, name);
1027
         }
1028
      }
1029
   }
1030

1031
   for (int i = 0; i < symtab->nsyms; i++) {
1032
      const struct nlist_64 *sym =
1033
         data + symtab->symoff + i * sizeof(struct nlist_64);
1034

1035
      if (sym->n_sect == NO_SECT || (sym->n_type & N_TYPE) != N_SECT)
1036
         continue;
1037

1038
      const char *name = data + symtab->stroff + sym->n_un.n_strx;
1039
      if (name[0] == '_' && icmp(blob->span->name, name + 1)) {
1040
         blob->span->entry = load_addr[sym->n_sect - 1] + sym->n_value;
1041
         break;
1042
      }
1043
   }
1044
}
1045
#elif !defined __MINGW32__
1046
static void code_load_elf(code_blob_t *blob, const void *data, size_t size)
7,130✔
1047
{
1048
   const Elf64_Ehdr *ehdr = data;
7,130✔
1049

1050
   if (ehdr->e_ident[EI_MAG0] != ELFMAG0
7,130✔
1051
       || ehdr->e_ident[EI_MAG1] != ELFMAG1
1052
       || ehdr->e_ident[EI_MAG2] != ELFMAG2
1053
       || ehdr->e_ident[EI_MAG3] != ELFMAG3)
7,130✔
1054
      fatal_trace("bad ELF magic");
×
1055
   else if (ehdr->e_shentsize != sizeof(Elf64_Shdr))
7,130✔
1056
      fatal_trace("bad section header size %d != %zu", ehdr->e_shentsize,
×
1057
                  sizeof(Elf64_Shdr));
1058

1059
   const Elf64_Shdr *strtab_hdr =
7,130✔
1060
      data + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize;
7,130✔
1061
   const char *strtab = data + strtab_hdr->sh_offset;
7,130✔
1062

1063
   void **load_addr LOCAL = xcalloc_array(ehdr->e_shnum, sizeof(void *));
14,260✔
1064

1065
   for (int i = 0; i < ehdr->e_shnum; i++) {
64,574✔
1066
      const Elf64_Shdr *shdr = data + ehdr->e_shoff + i * ehdr->e_shentsize;
57,444✔
1067

1068
      switch (shdr->sh_type) {
57,444✔
1069
      case SHT_PROGBITS:
14,742✔
1070
         if (shdr->sh_flags & SHF_ALLOC) {
14,742✔
1071
            code_blob_align(blob, shdr->sh_addralign);
7,612✔
1072
            load_addr[i] = blob->wptr;
7,612✔
1073
            code_blob_emit(blob, data + shdr->sh_offset, shdr->sh_size);
7,612✔
1074
         }
1075
         break;
1076

1077
      case SHT_RELA:
1078
         // Handled in second pass
1079
         break;
1080

1081
      case SHT_NULL:
1082
      case SHT_STRTAB:
1083
      case SHT_X86_64_UNWIND:
1084
         break;
1085

1086
      case SHT_SYMTAB:
1087
         for (int i = 0; i < shdr->sh_size / shdr->sh_entsize; i++) {
29,002✔
1088
            const Elf64_Sym *sym =
29,002✔
1089
               data + shdr->sh_offset + i * shdr->sh_entsize;
29,002✔
1090

1091
            if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
29,002✔
1092
               continue;
21,872✔
1093
            else if (!icmp(blob->span->name, strtab + sym->st_name))
7,130✔
1094
               continue;
×
1095
            else if (load_addr[sym->st_shndx] == NULL)
7,130✔
1096
               fatal_trace("missing section %d for symbol %s", sym->st_shndx,
×
1097
                           strtab + sym->st_name);
×
1098
            else {
1099
               blob->span->entry = load_addr[sym->st_shndx] + sym->st_value;
7,130✔
1100
               break;
7,130✔
1101
            }
1102
         }
1103
         break;
1104

1105
      default:
×
1106
         warnf("ignoring ELF section %s with type %x", strtab + shdr->sh_name,
×
1107
               shdr->sh_type);
1108
      }
1109
   }
1110

1111
   if (blob->overflow)
7,130✔
1112
      return;   // Relocations might point outside of code span
×
1113

1114
   for (int i = 0; i < ehdr->e_shnum; i++) {
64,574✔
1115
      const Elf64_Shdr *shdr = data + ehdr->e_shoff + i * ehdr->e_shentsize;
57,444✔
1116
      if (shdr->sh_type != SHT_RELA)
57,444✔
1117
         continue;
43,262✔
1118

1119
      const Elf64_Shdr *mod =
14,182✔
1120
         data + ehdr->e_shoff + shdr->sh_info * ehdr->e_shentsize;
14,182✔
1121
      if (mod->sh_type != SHT_PROGBITS || !(mod->sh_flags & SHF_ALLOC))
14,182✔
1122
         continue;
7,130✔
1123
      else if (load_addr[shdr->sh_info] == NULL)
7,052✔
1124
         fatal_trace("section %s not loaded", strtab + mod->sh_name);
×
1125

1126
      const Elf64_Shdr *symtab =
7,052✔
1127
         data + ehdr->e_shoff + shdr->sh_link * ehdr->e_shentsize;
7,052✔
1128
      if (symtab->sh_type != SHT_SYMTAB)
7,052✔
1129
         fatal_trace("section %s is not a symbol table",
×
1130
                     strtab + symtab->sh_name);
×
1131

1132
      const Elf64_Rela *endp = data + shdr->sh_offset + shdr->sh_size;
7,052✔
1133
      for (const Elf64_Rela *r = data + shdr->sh_offset; r < endp; r++) {
50,624✔
1134
         const Elf64_Sym *sym = data + symtab->sh_offset
43,572✔
1135
            + ELF64_R_SYM(r->r_info) * symtab->sh_entsize;
43,572✔
1136

1137
         char *ptr = NULL;
43,572✔
1138
         switch (ELF64_ST_TYPE(sym->st_info)) {
43,572✔
1139
         case STT_NOTYPE:
34,677✔
1140
         case STT_FUNC:
1141
            ptr = ffi_find_symbol(NULL, strtab + sym->st_name);
34,677✔
1142
            break;
34,677✔
1143
         case STT_SECTION:
8,895✔
1144
            ptr = load_addr[sym->st_shndx];
8,895✔
1145
            break;
8,895✔
1146
         }
1147

1148
         if (ptr == NULL && icmp(blob->span->name, strtab + sym->st_name))
43,572✔
1149
            ptr = (char *)blob->span->base;
37✔
1150

1151
         if (ptr == NULL)
43,572✔
1152
            fatal_trace("cannot resolve symbol %s type %d",
×
1153
                        strtab + sym->st_name, ELF64_ST_TYPE(sym->st_info));
×
1154

1155
         ptr += r->r_addend;
43,572✔
1156

1157
         void *patch = load_addr[shdr->sh_info] + r->r_offset;
43,572✔
1158
         assert(r->r_offset < mod->sh_size);
43,572✔
1159

1160
         switch (ELF64_R_TYPE(r->r_info)) {
43,572✔
1161
         case R_X86_64_64:
43,572✔
1162
            *(uint64_t *)patch = (uint64_t)ptr;
43,572✔
1163
            break;
43,572✔
1164
         case R_AARCH64_CALL26:
×
1165
            {
1166
               void *veneer = arm64_emit_trampoline(blob, (uintptr_t)ptr);
×
1167
               const ptrdiff_t pcrel = (veneer - patch) >> 2;
×
1168
               *(uint32_t *)patch &= ~0x3ffffff;
×
1169
               *(uint32_t *)patch |= pcrel & 0x3ffffff;
×
1170
            }
1171
            break;
×
1172
         case R_AARCH64_PREL64:
×
1173
            *(uint64_t *)patch = ptr - (char *)patch;
×
1174
            break;
×
1175
         case R_AARCH64_MOVW_UABS_G0_NC:
×
1176
            *(uint32_t *)patch |= ((uintptr_t)ptr & 0xffff) << 5;
×
1177
            break;
×
1178
         case R_AARCH64_MOVW_UABS_G1_NC:
×
1179
            *(uint32_t *)patch |= (((uintptr_t)ptr >> 16) & 0xffff) << 5;
×
1180
            break;
×
1181
         case R_AARCH64_MOVW_UABS_G2_NC:
×
1182
            *(uint32_t *)patch |= (((uintptr_t)ptr >> 32) & 0xffff) << 5;
×
1183
            break;
×
1184
         case R_AARCH64_MOVW_UABS_G3:
×
1185
            *(uint32_t *)patch |= (((uintptr_t)ptr >> 48) & 0xffff) << 5;
×
1186
            break;
×
1187
         default:
×
1188
            blob->span->size = blob->wptr - blob->span->base;
×
1189
            code_disassemble(blob->span, (uintptr_t)patch, NULL);
×
1190
            fatal_trace("cannot handle relocation type %ld for symbol %s",
×
1191
                        ELF64_R_TYPE(r->r_info), strtab + sym->st_name);
×
1192
         }
1193
      }
1194
   }
1195
}
1196
#endif
1197

1198
void code_load_object(code_blob_t *blob, const void *data, size_t size)
7,130✔
1199
{
1200
#if defined __APPLE__
1201
   code_load_macho(blob, data, size);
1202
#elif defined __MINGW32__
1203
   code_load_pe(blob, data, size);
1204
#else
1205
   code_load_elf(blob, data, size);
7,130✔
1206
#endif
1207
}
7,130✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc