master 6c74a7a1e71: Avoid a GOT indirection for constants in native code on ELF
Helmut Eller <[email protected]> Wed, 22 Jul 2026 16:09:38 -0400 (EDT)
| Newsgroups | gmane.emacs.diffs |
|---|---|
| Message-ID | <[email protected]> |
branch: master commit 6c74a7a1e71ca63acfbd8344837b3b5fa2b0b201 Author: Helmut Eller <[email protected]> Commit: Helmut Eller <[email protected]> Avoid a GOT indirection for constants in native code on ELF Make the d_reloc variable internal instead of external. For Lisp code like (defun foo () 'abc) the generated code used to look like // Pseudo code: extern Lisp_Object d_reloc[NCONST]; Lisp_Object foo (void) { return d_reloc[OFFSET_OF_ABC]; } // Assembler code: 0000000000001100 <F666f6f_foo_0>: 1100: mov 0x2ec1(%rip),%rax # 3fc8 <d_reloc-0x1b8> 1107: mov (%rax),%rax 110a: ret the new version looks like: // Pseudo code: static Lisp_Object d_reloc[NCONST]; extern Lisp_Object *d_reloc_addr (void) { return d_reloc; } Lisp_Object foo (void) { return d_reloc[OFFSET_OF_ABC]; } // Assembler code: 0000000000001120 <F666f6f_foo_0>: 1120: mov 0x3059(%rip),%rax # 4180 <d_reloc> 1127: ret where the function d_reloc_addr is used to initialize the d_reloc array and comp_unit->data_relocs. Note that the assembler code has one load less in the new version. (This is only true for ELF; PE and Mach-O don't need the indirection in the old version.) * src/comp.c (DATA_RELOC_ADDR_SYM, DATA_RELOC_EPHEMERAL_ADDR_SYM): New symbols. (declare_imported_data_relocs): Create the internal variable and the external function. (declare_imported_data): Supply the symbols for the functions. (find_relocs): New function. (check_comp_unit_relocs, load_comp_unit): Use it instead of a plain dynlib_sym. (ABI_VERSION): Bump version to 13. --- src/comp.c | 69 ++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/src/comp.c b/src/comp.c index b2b4fb6f222..80910cb3896 100644 --- a/src/comp.c +++ b/src/comp.c @@ -468,7 +468,7 @@ load_gccjit_if_necessary (bool mandatory) /* Increase this number to force a new Vcomp_abi_hash to be generated. */ -#define ABI_VERSION "12" +#define ABI_VERSION "13" /* Length of the hashes used for eln file naming. */ #define HASH_LENGTH 8 @@ -477,7 +477,9 @@ load_gccjit_if_necessary (bool mandatory) #define CURRENT_THREAD_RELOC_SYM "current_thread_reloc" #define F_SYMBOLS_WITH_POS_ENABLED_RELOC_SYM "f_symbols_with_pos_enabled_reloc" #define DATA_RELOC_SYM "d_reloc" +#define DATA_RELOC_ADDR_SYM "d_reloc_addr" #define DATA_RELOC_EPHEMERAL_SYM "d_reloc_eph" +#define DATA_RELOC_EPHEMERAL_ADDR_SYM "d_reloc_eph_addr" #define FUNC_LINK_TABLE_SYM "freloc_link_table" #define LINK_TABLE_HASH_SYM "freloc_hash" @@ -2850,31 +2852,42 @@ emit_static_object (const char *name, Lisp_Object obj) #pragma GCC diagnostic pop static reloc_array_t -declare_imported_data_relocs (Lisp_Object container, const char *code_symbol, +declare_imported_data_relocs (Lisp_Object container, + const char *code_symbol, + const char *addr_fun_symbol, const char *text_symbol) { /* Imported objects. */ - reloc_array_t res; - res.len = + EMACS_INT len = XFIXNUM (CALLNI (hash-table-count, CALLNI (comp-data-container-idx, container))); Lisp_Object d_reloc = CALLNI (comp-data-container-l, container); d_reloc = Fvconcat (1, &d_reloc); - res.r_val = - gcc_jit_lvalue_as_rvalue ( - gcc_jit_context_new_global ( - comp.ctxt, - NULL, - GCC_JIT_GLOBAL_EXPORTED, - gcc_jit_context_new_array_type (comp.ctxt, - NULL, - comp.lisp_obj_type, - res.len), - code_symbol)); - emit_static_object (text_symbol, d_reloc); + gcc_jit_type *d_reloc_type + = gcc_jit_context_new_array_type (comp.ctxt, NULL, + comp.lisp_obj_type, len); + gcc_jit_lvalue *d_reloc_lval + = gcc_jit_context_new_global (comp.ctxt, NULL, + GCC_JIT_GLOBAL_INTERNAL, + d_reloc_type, code_symbol); + gcc_jit_rvalue *d_reloc_rval + = gcc_jit_lvalue_as_rvalue (d_reloc_lval); + gcc_jit_rvalue *addr_rval + = gcc_jit_lvalue_get_address (d_reloc_lval, NULL); + gcc_jit_type *addr_rval_type = gcc_jit_rvalue_get_type (addr_rval); + gcc_jit_function *get_addr_fun + = gcc_jit_context_new_function (comp.ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + addr_rval_type, addr_fun_symbol, + 0, NULL, false); + gcc_jit_block *block + = gcc_jit_function_new_block (get_addr_fun, NULL); + gcc_jit_block_end_with_return (block, NULL, addr_rval); + + reloc_array_t res = { .len = len, .r_val = d_reloc_rval }; return res; } @@ -2885,10 +2898,12 @@ declare_imported_data (void) comp.data_relocs = declare_imported_data_relocs (CALLNI (comp-ctxt-d-default, Vcomp_ctxt), DATA_RELOC_SYM, + DATA_RELOC_ADDR_SYM, TEXT_DATA_RELOC_SYM); comp.data_relocs_ephemeral = declare_imported_data_relocs (CALLNI (comp-ctxt-d-ephemeral, Vcomp_ctxt), DATA_RELOC_EPHEMERAL_SYM, + DATA_RELOC_EPHEMERAL_ADDR_SYM, TEXT_DATA_RELOC_EPHEMERAL_SYM); } @@ -5170,13 +5185,25 @@ load_static_obj (struct Lisp_Native_Comp_Unit *comp_u, const char *name) } +static Lisp_Object * +find_relocs (dynlib_handle_ptr handle, const char *fun_sym) +{ + Lisp_Object *(*fun) (void) = dynlib_sym (handle, fun_sym); + if (!fun) + return NULL; + return fun (); +} + /* Return false when something is wrong or true otherwise. */ static bool check_comp_unit_relocs (struct Lisp_Native_Comp_Unit *comp_u) { dynlib_handle_ptr handle = comp_u->handle; - Lisp_Object *data_relocs = dynlib_sym (handle, DATA_RELOC_SYM); + Lisp_Object *data_relocs + = find_relocs (handle, DATA_RELOC_ADDR_SYM); + if (!data_relocs) + return false; EMACS_INT d_vec_len = XFIXNUM (Flength (comp_u->data_vec)); @@ -5215,8 +5242,9 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump, if (!saved_cu) xsignal1 (Qnative_lisp_file_inconsistent, comp_u->file); comp_u->loaded_once = !NILP (*saved_cu); - Lisp_Object *data_eph_relocs = - dynlib_sym (handle, DATA_RELOC_EPHEMERAL_SYM); + Lisp_Object *data_eph_relocs + = find_relocs (handle, DATA_RELOC_EPHEMERAL_ADDR_SYM); + eassert (data_eph_relocs); /* While resurrecting from an image dump loading more than once the same compilation unit does not make any sense. */ @@ -5254,7 +5282,8 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump, /* Always set data_imp_relocs pointer in the compilation unit (in can be used in 'dump_do_dump_relocation'). */ - comp_u->data_relocs = dynlib_sym (handle, DATA_RELOC_SYM); + comp_u->data_relocs = find_relocs (handle, DATA_RELOC_ADDR_SYM); + eassert (comp_u->data_relocs); if (!comp_u->loaded_once) {