summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-05-20 16:50:19 -0400
committerGHC GitLab CI <ghc-ci@gitlab-haskell.org>2022-05-23 16:24:07 -0400
commit1ca1efdc8758458a28414f6d00c679b8f9a6bd0a (patch)
tree4920de7dbbe621634157ef1fa7af8b8e1ad2ecfc
parent13b939e2ef4247887593e97e3eb4f2b4c7b05ef1 (diff)
downloadhaskell-1ca1efdc8758458a28414f6d00c679b8f9a6bd0a.tar.gz
jit object
(cherry picked from commit 9af5422203769f2f939d4a61e7de54b402863bc5)
-rw-r--r--rts/Linker.c2
-rw-r--r--rts/linker/BufferBuilder.c23
-rw-r--r--rts/linker/BufferBuilder.h37
-rw-r--r--rts/linker/JitObject.c97
-rw-r--r--rts/linker/JitObject.h5
-rw-r--r--rts/linker/JitObjectCoff.c47
-rw-r--r--rts/linker/JitObjectElf.c105
-rw-r--r--rts/rts.cabal.in9
8 files changed, 267 insertions, 58 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index e0a3a07dc2..b0ffa46688 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -1630,6 +1630,8 @@ int ocTryLoad (ObjectCode* oc) {
# endif
if (!r) { return r; }
+ register_jit_object(oc);
+
IF_DEBUG(linker, ocDebugBelch(oc, "protecting mappings\n"));
#if defined(NEED_SYMBOL_EXTRAS)
ocProtectExtras(oc);
diff --git a/rts/linker/BufferBuilder.c b/rts/linker/BufferBuilder.c
index 2c4f84836e..9f6ff04277 100644
--- a/rts/linker/BufferBuilder.c
+++ b/rts/linker/BufferBuilder.c
@@ -1,15 +1,12 @@
#include "Rts.h"
-
-struct BufferBuilder {
- uint8_t *buffer; // start of buffer
- uint8_t *head; // next unfilled byte
- uint8_t *end // end of buffer
-};
+#include "RtsUtils.h"
+#include "BufferBuilder.h"
+#include <string.h>
struct BufferBuilder buffer_builder_new(size_t initial_sz)
{
uint8_t *buffer = stgMallocBytes(initial_sz, "new_buffer_builder");
- return struct BufferBuilder {
+ return (struct BufferBuilder) {
.buffer = buffer,
.head = buffer,
.end = buffer + initial_sz,
@@ -62,15 +59,3 @@ void buffer_builder_append(struct BufferBuilder *bb, struct BufferBuilder *src)
buffer_builder_push(bb, bb->buffer, sz);
}
-#define DEFINE_BUILDER(ty) \
- void buffer_builder_#ty(struct BufferBuilder *bb, ty#_t x) \
- { return (ty#_t *) buffer_builder_push(bb, &x, sizeof(x)); }
-DEFINE_BUILDER(uint8)
-DEFINE_BUILDER(uint16)
-DEFINE_BUILDER(uint32)
-DEFINE_BUILDER(uint64)
-DEFINE_BUILDER(int8)
-DEFINE_BUILDER(int16)
-DEFINE_BUILDER(int32)
-DEFINE_BUILDER(int64)
-#undef DEFINE_BUILDER
diff --git a/rts/linker/BufferBuilder.h b/rts/linker/BufferBuilder.h
new file mode 100644
index 0000000000..facccb8335
--- /dev/null
+++ b/rts/linker/BufferBuilder.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct BufferBuilder {
+ uint8_t *buffer; // start of buffer
+ uint8_t *head; // next unfilled byte
+ uint8_t *end; // end of buffer
+};
+
+struct BufferBuilder buffer_builder_new(size_t initial_sz);
+void buffer_builder_free(struct BufferBuilder *bb);
+size_t buffer_builder_filled_size(struct BufferBuilder *bb);
+size_t buffer_builder_reserved_size(struct BufferBuilder *bb);
+void buffer_builder_realloc(struct BufferBuilder *bb, size_t new_sz);
+uint8_t *buffer_builder_push(struct BufferBuilder *bb, uint8_t *x, size_t sz);
+void buffer_builder_append(struct BufferBuilder *bb, struct BufferBuilder *src);
+
+#define buffer_builder_push_struct(bb, x) \
+ (typeof(x)*) buffer_builder_push(bb, (uint8_t *) &x, sizeof(x))
+
+#define DEFINE_BUILDER(ty) \
+ static inline ty ## _t* buffer_builder_ ## ty(struct BufferBuilder *bb, ty ## _t x) \
+ { return (ty ## _t *) buffer_builder_push(bb, (uint8_t *) &x, sizeof(x)); }
+
+DEFINE_BUILDER(uint8);
+DEFINE_BUILDER(uint16);
+DEFINE_BUILDER(uint32);
+DEFINE_BUILDER(uint64);
+DEFINE_BUILDER(int8);
+DEFINE_BUILDER(int16);
+DEFINE_BUILDER(int32);
+DEFINE_BUILDER(int64);
+
+#undef DEFINE_BUILDER
+
diff --git a/rts/linker/JitObject.c b/rts/linker/JitObject.c
index bd8b432f9e..48652283b7 100644
--- a/rts/linker/JitObject.c
+++ b/rts/linker/JitObject.c
@@ -1,43 +1,62 @@
#include "BufferBuilder.h"
+#include "JitObject.h"
+#include "LinkerInternals.h"
+#include "RtsUtils.h"
-void *build_jit_object_coff(ObjectCode *oc)
+/*
+ * GDB JIT interface
+ */
+
+typedef enum
+{
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry
{
- struct BufferBuilder bb = buffer_builder_new(4096);
-
- // COFF header
- buffer_builder_uint16(bb, IMAGE_FILE_MACHINE_AMD64);
- buffer_builder_uint16(bb, 1); // NumberOfSections
- buffer_builder_uint32(bb, 0); // TimeDateStamp
- uint32_t *ptr_to_symbol_table = buffer_builder_uint32(bb, 0); // PointerToSymbolTable
- buffer_builder_uint32(bb, n_syms); // NumberOfSymbols
- buffer_builder_uint16(bb, 0); // SizeOfOptionalHeader
- buffer_builder_uint16(bb, 0); // Characteristics
-
- // Sections
- buffer_builder_push(bb, ".text\0\0\0", 8); // Name
- buffer_builder_uint32(bb, sect_sz); // VirtualSize
- buffer_builder_uint32(bb, sect_base); // VirtualAddress
- buffer_builder_uint32(bb, 0); // SizeOfRawData
- buffer_builder_uint32(bb, 0); // PointerToRawData
- buffer_builder_uint32(bb, 0); // PointerToRelocations
- buffer_builder_uint32(bb, 0); // PointerToLinenumbers
- buffer_builder_uint16(bb, 0); // NumberOfRelocations
- buffer_builder_uint16(bb, 0); // NumberOfLinenumbers
- buffer_builder_uint32(bb, 0); // Characteristics
-
- struct BufferBuilder strings = buffer_builder_new(4096);
- for (int i=0; i < oc->n_symbols; i++) {
- Symbol_t *sym = oc->symbols[i];
- size_t offset = buffer_builder_filled_size(strings);
- buffer_builder_push(strings, sym->name);
- buffer_builder_uint32(bb, 0);
- buffer_builder_uint32(bb, offset); // RawName index
- buffer_builder_uint32(bb, value); // Value
- buffer_builder_uint16(bb, 1); // SectionNumber
- buffer_builder_uint8(bb, 0x20); // StorageClass
- buffer_builder_uint8(bb, 0); // NumberOfAuxSymbols
- }
-
- buffer_builder_append(bb, strings);
- return bb->start;
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+};
+
+struct jit_descriptor
+{
+ uint32_t version;
+ /* This type should be jit_actions_t, but we use uint32_t
+ to be explicit about the bitwidth. */
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+/* GDB puts a breakpoint in this function. */
+void __jit_debug_register_code(void);
+void __attribute__((noinline)) __jit_debug_register_code() { };
+
+/* Make sure to specify the version statically, because the
+ debugger may check the version before we can set it. */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+/*
+ * Registering a JIT object
+ */
+
+void register_jit_object(ObjectCode *oc)
+{
+ struct BufferBuilder buf = build_jit_object(oc);
+
+ struct jit_code_entry *code_entry = stgMallocBytes(sizeof(struct jit_code_entry), "register_jit_object");
+ code_entry->next_entry = __jit_debug_descriptor.first_entry;
+ code_entry->prev_entry = NULL;
+ code_entry->symfile_addr = (const char *) buf.buffer;
+ code_entry->symfile_size = buffer_builder_filled_size(&buf);
+
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+ __jit_debug_descriptor.first_entry = code_entry;
+ __jit_debug_descriptor.relevant_entry = code_entry;
+ __jit_debug_register_code();
}
+
diff --git a/rts/linker/JitObject.h b/rts/linker/JitObject.h
new file mode 100644
index 0000000000..1f21ee28c8
--- /dev/null
+++ b/rts/linker/JitObject.h
@@ -0,0 +1,5 @@
+#include "LinkerInternals.h"
+#include "BufferBuilder.h"
+
+void register_jit_object(ObjectCode *oc);
+struct BufferBuilder build_jit_object(ObjectCode *oc);
diff --git a/rts/linker/JitObjectCoff.c b/rts/linker/JitObjectCoff.c
new file mode 100644
index 0000000000..77ce9fecc9
--- /dev/null
+++ b/rts/linker/JitObjectCoff.c
@@ -0,0 +1,47 @@
+#include "BufferBuilder.h"
+#include "JitObject.h"
+#include "LinkerInternals.h"
+#include "RtsUtils.h"
+
+struct BufferBuilder build_jit_object(ObjectCode *oc)
+{
+ struct BufferBuilder bb = buffer_builder_new(4096);
+
+ // COFF header
+ buffer_builder_uint16(&bb, IMAGE_FILE_MACHINE_AMD64);
+ buffer_builder_uint16(&bb, 1); // NumberOfSections
+ buffer_builder_uint32(&bb, 0); // TimeDateStamp
+ uint32_t *ptr_to_symbol_table = buffer_builder_uint32(&bb, 0); // PointerToSymbolTable
+ buffer_builder_uint32(&bb, n_syms); // NumberOfSymbols
+ buffer_builder_uint16(&bb, 0); // SizeOfOptionalHeader
+ buffer_builder_uint16(&bb, 0); // Characteristics
+
+ // Sections
+ buffer_builder_push(&bb, ".text\0\0\0", 8); // Name
+ buffer_builder_uint32(&bb, sect_sz); // VirtualSize
+ buffer_builder_uint32(&bb, sect_base); // VirtualAddress
+ buffer_builder_uint32(&bb, 0); // SizeOfRawData
+ buffer_builder_uint32(&bb, 0); // PointerToRawData
+ buffer_builder_uint32(&bb, 0); // PointerToRelocations
+ buffer_builder_uint32(&bb, 0); // PointerToLinenumbers
+ buffer_builder_uint16(&bb, 0); // NumberOfRelocations
+ buffer_builder_uint16(&bb, 0); // NumberOfLinenumbers
+ buffer_builder_uint32(&bb, 0); // Characteristics
+
+ struct BufferBuilder strings = buffer_builder_new(4096);
+ for (int i=0; i < oc->n_symbols; i++) {
+ Symbol_t *sym = &oc->symbols[i];
+ size_t offset = buffer_builder_filled_size(&strings);
+ buffer_builder_push(&strings, sym->name, strlen(sym->name));
+ buffer_builder_uint32(&bb, 0);
+ buffer_builder_uint32(&bb, offset); // RawName index
+ buffer_builder_uint32(&bb, value); // Value
+ buffer_builder_uint16(&bb, 1); // SectionNumber
+ buffer_builder_uint8(&bb, 0x20); // StorageClass
+ buffer_builder_uint8(&bb, 0); // NumberOfAuxSymbols
+ }
+
+ buffer_builder_append(&bb, strings);
+ return bb;
+}
+
diff --git a/rts/linker/JitObjectElf.c b/rts/linker/JitObjectElf.c
new file mode 100644
index 0000000000..41653ad45e
--- /dev/null
+++ b/rts/linker/JitObjectElf.c
@@ -0,0 +1,105 @@
+#include "BufferBuilder.h"
+#include "elf_compat.h"
+#include "linker/Elf.h"
+#include "JitObject.h"
+#include "LinkerInternals.h"
+#include "RtsUtils.h"
+
+#include <string.h>
+
+#define TEXT_SECTION_IDX 1
+
+struct BufferBuilder build_jit_object(ObjectCode *oc)
+{
+ struct BufferBuilder bb = buffer_builder_new(4096);
+
+ // ELF header
+ Elf64_Ehdr ehdr = {
+ .e_ident = {
+ ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
+ ELFCLASS64,
+ ELFDATA2LSB,
+ EV_CURRENT,
+ },
+ .e_type = ET_REL,
+ .e_machine = EM_386,
+ .e_version = EV_CURRENT,
+ .e_entry = 0,
+ .e_phoff = 0,
+ .e_shoff = 0, // will be filled in later
+ .e_flags = 0,
+ .e_ehsize = sizeof(Elf64_Ehdr),
+ .e_phentsize = sizeof(Elf64_Phdr),
+ .e_phnum = 0,
+ .e_shentsize = sizeof(Elf64_Shdr),
+ .e_shnum = 2,
+ .e_shstrndx = 0,
+ };
+
+ Elf64_Ehdr *ehdr_ptr = buffer_builder_push_struct(&bb, ehdr);
+
+ // String table
+ struct BufferBuilder strings = buffer_builder_new(4096);
+ buffer_builder_uint8(&strings, 0);
+
+ // Section table
+ struct BufferBuilder shtab = buffer_builder_new(4096);
+ Elf64_Shdr shtab_zero_ent = {
+ .sh_name = 0,
+ .sh_type = SHT_NULL,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = SHN_UNDEF,
+ .sh_info = 0,
+ .sh_addralign = 0,
+ .sh_entsize = 0,
+ };
+ buffer_builder_push_struct(&shtab, shtab_zero_ent);
+
+ Elf64_Shdr shtab_text_ent = {
+ .sh_name = 1,
+ .sh_type = SHT_NULL,
+ .sh_flags = SHF_ALLOC | SHF_EXECINSTR,
+ .sh_addr = 0,
+ .sh_offset = 0, // will be filled in later
+ .sh_size = 0,
+ .sh_link = SHN_UNDEF,
+ .sh_info = 0,
+ .sh_addralign = 0,
+ .sh_entsize = 0,
+ };
+ buffer_builder_push_struct(&shtab, shtab_zero_ent);
+
+ // Symbol table
+ struct BufferBuilder symtab = buffer_builder_new(4096);
+ Elf64_Sym symtab_zero_ent = {
+ .st_name = 0,
+ .st_value = 0,
+ .st_size = 0,
+ .st_info = 0,
+ .st_other = 0,
+ .st_shndx = SHN_UNDEF,
+ };
+ buffer_builder_push_struct(&symtab, symtab_zero_ent);
+
+ for (int i=0; i < oc->n_symbols; i++) {
+ Symbol_t *sym = &oc->symbols[i];
+ size_t sym_name_offset = buffer_builder_filled_size(&strings);
+ buffer_builder_push(&strings, sym->name, strlen(sym->name)+1);
+
+ Elf64_Sym symtab_ent = {
+ .st_name = sym_name_offset,
+ .st_value = hi,
+ .st_size = 0,
+ .st_info = 0,
+ .st_other = 0,
+ .st_shndx = TEXT_SECTION_IDX,
+ };
+ buffer_builder_push_struct(&symtab, symtab_ent);
+ }
+
+ return bb;
+}
+
diff --git a/rts/rts.cabal.in b/rts/rts.cabal.in
index cc449ee522..e2f0bf11fa 100644
--- a/rts/rts.cabal.in
+++ b/rts/rts.cabal.in
@@ -470,6 +470,13 @@ library
if arch(ppc) || arch(ppc64) || arch(s390x) || arch(riscv64)
asm-sources: StgCRunAsm.S
+ -- gdb JIT object logic
+ if os(mingw32)
+ c-sources: linker/JitObjectCoff.c
+ else
+ if os(linux) || os(freebsd)
+ c-sources: linker/JitObjectElf.c
+
c-sources: Adjustor.c
adjustor/AdjustorPool.c
ExecPage.c
@@ -548,8 +555,10 @@ library
hooks/OnExit.c
hooks/OutOfHeap.c
hooks/StackOverflow.c
+ linker/BufferBuilder.c
linker/CacheFlush.c
linker/Elf.c
+ linker/JitObject.c
linker/LoadArchive.c
linker/M32Alloc.c
linker/MMap.c