From 489d3f50afd25bb4dbd67271cee8f8a2ee5563f4 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Fri, 9 Feb 2018 16:09:05 +0000 Subject: [PATCH 01/15] Remove default for -base and apply to all ports Previously: - -base applied to MSVC64 - Cygwin64 had -base 0x10000 hard-coded until #89 - mingw64 didn't specify -base at all Now: - The default is not to change the base address at all - All 3 64-bit ports support -base - For now, still ignored for 32-bit ports --- CHANGES | 3 +++ cmdline.ml | 4 ++-- reloc.ml | 14 +++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 22f86c1..6d16925 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,7 @@ Next version +- GPR#52: -base option consistently applied to mingw64, cygwin64 and msvc64. + Default is no longer specified, making msvc64 consistent with the other two + ports (David Allsopp) - GPR#127: Recognise hyphens in option names in the COFF .drectve section. Fixes #126 (Reza Barazesh) - GPR#136: Fix parallel access crashes and misbehavior (David Allsopp, Jan Midtgaard, Antonin Décimo) - GPR#140: Fixes #29. Support relocation kind 0003 (IMAGE_REL_AMD64_ADDR32NB) and diff --git a/cmdline.ml b/cmdline.ml index 1d23053..50766ba 100644 --- a/cmdline.ml +++ b/cmdline.ml @@ -44,7 +44,7 @@ let implib = ref false let deffile = ref None let stack_reserve = ref None let no_rel_relocs = ref false -let base_addr = ref "0x10000" +let base_addr = ref None let usage_msg = Printf.sprintf @@ -86,7 +86,7 @@ let specs = [ "-norelrelocs", Arg.Set no_rel_relocs, " Ensure that no relative relocation is generated"; - "-base", Arg.String (fun s -> base_addr := s), + "-base", Arg.String (fun s -> base_addr := Some s), " Specify base address (Win64 only)"; "-pthread", Arg.Unit (fun () -> extra_args := "-pthread" :: !extra_args), diff --git a/reloc.ml b/reloc.ml index 9b3c8ca..db6a26c 100644 --- a/reloc.ml +++ b/reloc.ml @@ -1116,7 +1116,9 @@ let build_dll link_exe output_file files exts extra_args = in let extra_args = - if !machine = `x64 then (Printf.sprintf "/base:%s " !base_addr) ^ extra_args else extra_args + match !machine, !base_addr with + | `x64, Some base_addr -> Printf.sprintf "/base:%s %s" base_addr extra_args + | _ -> extra_args in let extra_args = @@ -1161,6 +1163,11 @@ let build_dll link_exe output_file files exts extra_args = close_out oc; Filename.quote def_file in + let extra_args = + match !machine, !base_addr with + | `x64, Some base_addr -> Printf.sprintf "-Xlinker --image-base -Xlinker %s %s" base_addr extra_args + | _ -> extra_args + in Printf.sprintf "%s %s%s -L. %s %s -o %s %s %s %s %s" !gcc @@ -1182,6 +1189,11 @@ let build_dll link_exe output_file files exts extra_args = close_out oc; Filename.quote def_file in + let extra_args = + match !machine, !base_addr with + | `x64, Some base_addr -> Printf.sprintf "-Xlinker --image-base -Xlinker %s %s" base_addr extra_args + | _ -> extra_args + in Printf.sprintf "%s -m%s %s%s -L. %s %s -o %s %s %s %s %s %s" !gcc From fc6858d9b5b0c11cca98ca948bd911a73ef0d34e Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sat, 10 Feb 2018 10:04:36 +0000 Subject: [PATCH 02/15] Add jmptbl section for RELOC trampolines An additional executable section is added to each executable containing 16 bytes for each external symbol. This can then be used by flexdll_relocate_v2 if a RELOC_REL32 refers to a function more than 2GiB away. --- reloc.ml | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/reloc.ml b/reloc.ml index db6a26c..b2e6f5e 100644 --- a/reloc.ml +++ b/reloc.ml @@ -410,7 +410,7 @@ module StrSet = Set.Make(String) by their name). It also lists segments that are normally write-protected and that must be de-protected to enable the patching process. *) -let add_reloc_table obj obj_name p = +let add_reloc_table obj obj_name p trampolines = let sname = Symbol.gen_sym () in (* symbol pointing to the reloc table *) let sect = Section.create ".reltbl" 0xc0300040l in let data = Buffer.create 1024 in @@ -432,33 +432,33 @@ let add_reloc_table obj obj_name p = rtype - https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#x64-processors *) - let kind = match !machine, rel.rtype with + let kind, may_trampoline = match !machine, rel.rtype with | `x86, 0x06 (* IMAGE_REL_I386_DIR32 *) | `x64, 0x01 (* IMAGE_REL_AMD64_ADDR64 *) -> - 0x0002 (* absolute, native size (32/64) *) + 0x0002, false (* absolute, native size (32/64) *) | `x86, 0x07 (* IMAGE_REL_I386_DIR32NB *) | `x64, 0x03 (* IMAGE_REL_AMD64_ADDR32NB *) -> - 0x0007 (* 32nb *) + 0x0007, true (* 32nb *) | `x64, 0x04 (* IMAGE_REL_AMD64_REL32 *) | `x86, 0x14 (* IMAGE_REL_I386_REL32 *) when not !no_rel_relocs -> - 0x0001 (* rel32 *) + 0x0001, true (* rel32 *) | `x64, 0x05 (* IMAGE_REL_AMD64_REL32_1 *) when not !no_rel_relocs-> - 0x0004 (* rel32_1 *) + 0x0004, true (* rel32_1 *) | `x64, 0x06 (* IMAGE_REL_AMD64_REL32_2 *) when not !no_rel_relocs-> - 0x0005 (* rel32_2 *) + 0x0005, true (* rel32_2 *) | `x64, 0x07 (* IMAGE_REL_AMD64_REL32_3 *) when not !no_rel_relocs-> - 0x0008 (* rel32_3 *) + 0x0008, true (* rel32_3 *) | `x64, 0x08 (* IMAGE_REL_AMD64_REL32_4 *) when not !no_rel_relocs-> - 0x0003 (* rel32_4 *) + 0x0003, true (* rel32_4 *) | `x64, 0x09 (* IMAGE_REL_AMD64_REL32_5 *) when not !no_rel_relocs-> - 0x0006 (* rel32_5 *) + 0x0006, true (* rel32_5 *) | (`x86 | `x64), (0x0a (* IMAGE_REL_{I386|AMD64}_SECTION *) | 0x0b (* IMAGE_REL_{I386|AMD64}_SECREL*) ) -> - 0x0100 (* debug relocs: ignore *) + 0x0100, false (* debug relocs: ignore *) | _, k -> let msg = @@ -469,6 +469,7 @@ let add_reloc_table obj obj_name p = (* Printf.eprintf "%s\n%!" msg; 0x0001 *) in + if may_trampoline then trampolines := StrSet.add rel.symbol.sym_name !trampolines; int_to_buf data kind; (* name *) @@ -605,6 +606,12 @@ let add_master_reloc_table obj names symname = sect.data <- `String (Buffer.to_bytes data); obj.sections <- sect :: obj.sections +let add_master_jmp_table obj names symname = + let trampolines = StrSet.cardinal names in + let sect = Section.create ".mjmptbl" 0xe0500020l in + obj.symbols <- (Symbol.export symname sect 0l) :: obj.symbols; + sect.data <- `Uninit (trampolines * 16); + obj.sections <- sect :: obj.sections let collect_dllexports obj = @@ -851,7 +858,7 @@ let build_dll link_exe output_file files exts extra_args = List.iter (fun fn -> collect_file (find_file fn)) exts; if main_pgm then add_def (usym "static_symtable") - else add_def (usym "reloctbl"); + else (add_def (usym "reloctbl"); add_def (usym "jmptbl")); if !machine = `x64 then add_def "__ImageBase" else add_def "___ImageBase"; @@ -909,6 +916,7 @@ let build_dll link_exe output_file files exts extra_args = let libobjects = Hashtbl.create 16 in let reloctbls = ref [] in + let trampolines = ref StrSet.empty in let exported = ref StrSet.empty in List.iter (fun s -> exported := StrSet.add (usym s) !exported) !defexports; @@ -929,7 +937,7 @@ let build_dll link_exe output_file files exts extra_args = Printf.printf "** Imported symbols for %s:\n%!" name; StrSet.iter print_endline imps ); - let sym = add_reloc_table obj name (fun s -> StrSet.mem s.sym_name imps) in + let sym = add_reloc_table obj name (fun s -> StrSet.mem s.sym_name imps) trampolines in reloctbls := sym :: !reloctbls in @@ -1035,7 +1043,10 @@ let build_dll link_exe output_file files exts extra_args = add_export_table obj (if !noexport then [] else StrSet.elements !exported) (usym (if main_pgm then "static_symtable" else "symtbl")); - if not main_pgm then add_master_reloc_table obj !reloctbls (usym "reloctbl"); + if not main_pgm then begin + add_master_reloc_table obj !reloctbls (usym "reloctbl"); + add_master_jmp_table obj !trampolines (usym "jmptbl"); + end; if !errors then exit 2; @@ -1139,7 +1150,7 @@ let build_dll link_exe output_file files exts extra_args = "link /nologo %s%s%s%s%s /implib:%s /out:%s /subsystem:%s %s %s %s" (if !verbose >= 2 then "/verbose " else "") (if link_exe = `EXE then "" else "/dll ") - (if main_pgm then "" else "/export:symtbl /export:reloctbl ") + (if main_pgm then "" else "/export:symtbl /export:reloctbl /export:jmptbl ") (if main_pgm then "" else if !noentry then "/noentry " else let s = match !machine with @@ -1159,7 +1170,7 @@ let build_dll link_exe output_file files exts extra_args = if main_pgm then "" else let def_file, oc = open_temp_file "flexlink" ".def" in - Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n"; + Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n jmptbl\n"; close_out oc; Filename.quote def_file in @@ -1185,7 +1196,7 @@ let build_dll link_exe output_file files exts extra_args = if main_pgm then "" else let def_file, oc = open_temp_file "flexlink" ".def" in - Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n"; + Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n jmptbl\n"; close_out oc; Filename.quote def_file in From 8ee8b15624b58bd6a7f2876f5ed5e1616d03c971 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sat, 10 Feb 2018 10:47:17 +0000 Subject: [PATCH 03/15] Alter resolver to return entire symbol struct --- flexdll.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/flexdll.c b/flexdll.c index edada97..b4a6774 100644 --- a/flexdll.c +++ b/flexdll.c @@ -51,7 +51,7 @@ typedef struct dlunit { int count; struct dlunit *next,*prev; } dlunit; -typedef void *resolver(void*, const char*); +typedef dynsymbol *resolver(void*, const char*); static HANDLE units_mutex = INVALID_HANDLE_VALUE; @@ -267,6 +267,7 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { SYSTEM_INFO si; char *page_start, *page_end; char *prev_page_start = (char*)1, *prev_page_end = (char*)1; + dynsymbol *sym; if (!tbl) return; @@ -278,12 +279,13 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { for (ptr = tbl->entries; ptr->kind; ptr++) { if (ptr->kind & RELOC_DONE) continue; - s = (UINT_PTR) f(data,ptr->name); - if (!s) { + sym = f(data, ptr->name); + if (!sym) { err->code = 2; cannot_resolve_msg(ptr->name, err); goto restore; } + s = (UINT_PTR)sym->addr; /* Set up page protection to allow the relocation. We will undo the change on the next relocation if it falls in a different @@ -432,7 +434,7 @@ static int compare_dynsymbol(const void *s1, const void *s2) { return strcmp(((dynsymbol*) s1) -> name, ((dynsymbol*) s2) -> name); } -static void *find_symbol(symtbl *tbl, const char *name) { +static dynsymbol *find_symbol(symtbl *tbl, const char *name) { static dynsymbol s; dynsymbol *sym; @@ -442,7 +444,7 @@ static void *find_symbol(symtbl *tbl, const char *name) { sym = bsearch(&s,&tbl->entries,tbl->size, sizeof(dynsymbol),&compare_dynsymbol); - return (NULL == sym ? NULL : sym -> addr); + return sym; } @@ -467,8 +469,8 @@ static void unlink_unit(dlunit *unit) { if (unit->next) unit->next->prev=unit->prev; } -static void *find_symbol_global(void *data, const char *name) { - void *sym; +static dynsymbol *find_symbol_global(void *data, const char *name) { + dynsymbol *sym; dlunit *unit; (void)data; /* data is unused */ @@ -616,7 +618,7 @@ void flexdll_dlclose(void *u) { void *flexdll_dlsym(void *u, const char *name) { - void *res; + dynsymbol *res; err_t * err; err = get_tls_error(TLS_ERROR_NOP); if (err == NULL) return NULL; @@ -629,7 +631,7 @@ void *flexdll_dlsym(void *u, const char *name) { else if (NULL == u) res = find_symbol(&static_symtable,name); else res = find_symbol(((dlunit*)u)->symtbl,name); ReleaseMutex(units_mutex); - return res; + return (res ? res->addr : NULL); } char *flexdll_dlerror(void) { From 14de2454805ebc474eb90ab8687275d3dd3ec0d9 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sat, 10 Feb 2018 10:56:23 +0000 Subject: [PATCH 04/15] Factor out environment setting code in dlopen --- flexdll.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/flexdll.c b/flexdll.c index b4a6774..37ee869 100644 --- a/flexdll.c +++ b/flexdll.c @@ -501,6 +501,28 @@ int flexdll_relocate(void *tbl) { return 1; } +void set_env_ptr(char* name, void* ptr) { + char env[256]; + +#if defined(CYGWIN) || __STDC_SECURE_LIB__ >= 200411L + sprintf(env, "%p", ptr); +#endif + +#ifdef CYGWIN + setenv(name, env, 1); +#elif __STDC_SECURE_LIB__ >= 200411L + _putenv_s(name, env); +#else + { + char* s; + sprintf(env, "%s=%p", name, relocate); + s = malloc(strlen(env) + 1); + strcpy(s, env); + putenv(s); + } +#endif +} + #ifdef CYGWIN void *flexdll_dlopen(const char *file, int mode) { #else @@ -508,32 +530,14 @@ void *flexdll_wdlopen(const wchar_t *file, int mode) { #endif void *handle; dlunit *unit; - char flexdll_relocate_env[256]; int exec = (mode & FLEXDLL_RTLD_NOEXEC ? 0 : 1); - void* relocate = (exec ? &flexdll_relocate : 0); err_t * err; err = get_tls_error(TLS_ERROR_RESET); if(err == NULL) return NULL; if (!file) return &main_unit; -#ifdef CYGWIN - sprintf(flexdll_relocate_env,"%p",relocate); - setenv("FLEXDLL_RELOCATE", flexdll_relocate_env, 1); -#else -#if __STDC_SECURE_LIB__ >= 200411L - sprintf(flexdll_relocate_env,"%p",relocate); - _putenv_s("FLEXDLL_RELOCATE", flexdll_relocate_env); -#else - { - char* s; - sprintf(flexdll_relocate_env,"FLEXDLL_RELOCATE=%p",relocate); - s = malloc(strlen(flexdll_relocate_env) + 1); - strcpy(s, flexdll_relocate_env); - putenv(s); - } -#endif /* __STDC_SECURE_LIB__ >= 200411L*/ -#endif /* CYGWIN */ + set_env_ptr("FLEXDLL_RELOCATE", (exec ? &flexdll_relocate : 0)); again: if (units_mutex == INVALID_HANDLE_VALUE) { From c800efebe83094ca56a80fe542d0aeb1ec3539d1 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sat, 10 Feb 2018 11:04:23 +0000 Subject: [PATCH 05/15] Use trampolines for RELOC_REL32 > 2GiB relocate function now takes a pointer to the jmptbl page allocated in the image being loaded. If a RELOC_REL32 relocation is encountered where the offset is greater than 2GiB then 16 bytes of the page is used to generate a trampoline to the function. The new functionality is exposed as flexdll_relocate_v2 and passed in the FLEXDLL_RELOCATE_V2 environment variable. The old flexdll_relocate pointer is still passed in FLEXDLL_RELOCATE by flexdll_dlopen meaning that an executable compiled with this new version can still load DLLs compiled with older versions (these will simply fail if the relocations are too far away, as before). Similarly, flexdll_init falls back to FLEXDLL_RELOCATE if FLEXDLL_RELOCATE_V2 is not set meaning that a DLL compiled with this new version can also be loaded by an executable compiled with older versions. The symbol table now has to be copied to be augmented with an extra pointer for the trampoline, as the symtbl itself cannot be changed without breaking this backwards compatibility. --- CHANGES | 6 ++ flexdll.c | 165 +++++++++++++++++++++++++++-------------------- flexdll_initer.c | 21 ++++-- 3 files changed, 117 insertions(+), 75 deletions(-) diff --git a/CHANGES b/CHANGES index 6d16925..bbe9c61 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,12 @@ Next version - GPR#52: -base option consistently applied to mingw64, cygwin64 and msvc64. Default is no longer specified, making msvc64 consistent with the other two ports (David Allsopp) +- GPR#52: 64-bit ports can now always process RELOC_REL32* jumps by generating + trampolines for cases where the relocations are more than 32GiB away. New + functionality passed as flexdll_relocate_v2, which allows mixing executables + and DLLs compiled with and without the new features. If either executable or + DLL lacks the flexdll_relocate_v2 support, then it falls back to the previous + error message if a RELOC_REL32 is more than 2GiB away. (David Allsopp) - GPR#127: Recognise hyphens in option names in the COFF .drectve section. Fixes #126 (Reza Barazesh) - GPR#136: Fix parallel access crashes and misbehavior (David Allsopp, Jan Midtgaard, Antonin Décimo) - GPR#140: Fixes #29. Support relocation kind 0003 (IMAGE_REL_AMD64_ADDR32NB) and diff --git a/flexdll.c b/flexdll.c index 37ee869..6e29e10 100644 --- a/flexdll.c +++ b/flexdll.c @@ -42,7 +42,9 @@ typedef unsigned long uintnat; typedef struct { UINT_PTR kind; char *name; UINT_PTR *addr; } reloc_entry; typedef struct { char *first; char *last; DWORD old; } nonwr; typedef struct { nonwr *nonwr; reloc_entry entries[]; } reloctbl; -typedef struct { void *addr; char *name; } dynsymbol; +typedef struct { void *addr; char *name; } symtbl_entry; +typedef struct { void *addr; char *name; void *trampoline; } dynsymbol; +typedef struct { UINT_PTR size; symtbl_entry entries[]; } raw_symtbl; typedef struct { UINT_PTR size; dynsymbol entries[]; } symtbl; typedef struct dlunit { void *handle; @@ -259,7 +261,7 @@ static void cannot_resolve_msg(char *name, err_t *err) { err->message[l+n] = 0; } -static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { +static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t *err) { reloc_entry *ptr; INT_PTR s; DWORD prev_protect; @@ -268,6 +270,8 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { char *page_start, *page_end; char *prev_page_start = (char*)1, *prev_page_end = (char*)1; dynsymbol *sym; + int rel_offset; + char *reloc_type; if (!tbl) return; @@ -322,81 +326,70 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { switch (ptr->kind & 0xff) { case RELOC_ABS: - *(ptr->addr) += s; + rel_offset = -1; break; case RELOC_REL32: - s -= (INT_PTR)(ptr -> addr) + 4; - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate %s RELOC_REL32, target is too far: %p %p", ptr->name, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 4; + reloc_type = "REL32"; break; case RELOC_REL32_1: - s -= (INT_PTR)(ptr -> addr) + 5; - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_REL32_1, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 5; + reloc_type = "REL32_1"; break; case RELOC_REL32_2: - s -= (INT_PTR)(ptr -> addr) + 6; - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_REL32_2, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 6; + reloc_type = "REL32_2"; break; case RELOC_REL32_3: - s -= (INT_PTR)(ptr -> addr) + 7; - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_REL32_3, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 7; + reloc_type = "REL32_3"; break; case RELOC_REL32_4: - s -= (INT_PTR)(ptr -> addr) + 8; - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_REL32_4, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 8; + reloc_type = "REL32_4"; break; case RELOC_REL32_5: - s -= (INT_PTR)(ptr -> addr) + 9; - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_REL32_5, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 9; + reloc_type = "REL32_5"; break; case RELOC_32NB: - s += *((INT32*) ptr -> addr); - if (s != (INT32) s) { - sprintf(err->message, "flexdll error: cannot relocate %s RELOC_32NB, target is too far: %p %p", ptr->name, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - goto restore; - } - *((UINT32*) ptr->addr) = (INT32) s; + rel_offset = 0; + reloc_type = "32NB"; break; default: fprintf(stderr, "flexdll: unknown relocation kind"); exit(2); } + + if (rel_offset < 0) { + *(ptr->addr) += s; + } else { + if (rel_offset) + s -= (INT_PTR)(ptr -> addr) + rel_offset; + s += *((INT32*) ptr -> addr); + if (s != (INT32) s) { + if (jmptbl) { + if (!sym->trampoline) { + void* trampoline = sym->trampoline = *jmptbl; + /* movq $(sym->addr), %rax */ + *((short*)trampoline) = 0xb848; + *((UINT_PTR*)(trampoline + 2)) = (UINT_PTR)sym->addr; + /* jmp %rax */ + *((short*)(trampoline + 10)) = 0xe0ff; + *jmptbl += 16; + } + s = (UINT_PTR)(sym->trampoline); + s -= (INT_PTR)(ptr->addr) + rel_offset; + s += *((INT32*)ptr->addr); + } else { + sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far: %p %p", + reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); + err->code = 3; + return; + } + } + *((UINT32*) ptr->addr) = (INT32)s; + } ptr->kind |= RELOC_DONE; } restore: @@ -409,8 +402,10 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { } } -static void relocate_master(resolver f, void *data, reloctbl **ptr, err_t *err) { - while (0 == err->code && *ptr) relocate(f,data,*ptr++,err); +static void relocate_master(resolver f, void *data, reloctbl **ptr, void *jmptbl, err_t *err) { + void **pjmptbl = jmptbl ? &jmptbl : NULL; + while (0 == err->code && *ptr) + relocate(f, data, *ptr++, pjmptbl, err); } /* Symbol tables */ @@ -451,7 +446,7 @@ static dynsymbol *find_symbol(symtbl *tbl, const char *name) { /* API */ -extern symtbl static_symtable; +extern raw_symtbl static_symtable; static dlunit *units = NULL; static dlunit main_unit; @@ -469,13 +464,40 @@ static void unlink_unit(dlunit *unit) { if (unit->next) unit->next->prev=unit->prev; } +static symtbl *augment_symtbl(raw_symtbl *raw_symtbl) { + symtbl *result; + dynsymbol *ptr; + symtbl_entry *src; + int i; + result = (symtbl*)malloc(raw_symtbl->size * sizeof(dynsymbol) + sizeof(UINT_PTR)); + ptr = result->entries; + src = raw_symtbl->entries; + result->size = raw_symtbl->size; + i = (int)result->size; + while (i-- > 0) { + ptr->addr = src->addr; + ptr->name = (src++)->name; + (ptr++)->trampoline = NULL; + } + return result; +} + +static symtbl *get_static_symtable(void) { + static symtbl *table = NULL; + + if (table) + return table; + else + return (table = augment_symtbl(&static_symtable)); +} + static dynsymbol *find_symbol_global(void *data, const char *name) { dynsymbol *sym; dlunit *unit; (void)data; /* data is unused */ if (!name) return NULL; - sym = find_symbol(&static_symtable, name); + sym = find_symbol(get_static_symtable(), name); if (sym) return sym; for (unit = units; unit; unit = unit->next) { @@ -490,17 +512,19 @@ static dynsymbol *find_symbol_global(void *data, const char *name) { return NULL; } -int flexdll_relocate(void *tbl) { +int flexdll_relocate_v2(void *tbl, void *jmptbl) { err_t * err; err = get_tls_error(TLS_ERROR_RESET); if(err == NULL) return 0; if (!tbl) { printf("No master relocation table\n"); return 0; } - relocate_master(find_symbol_global, NULL, tbl, err); + relocate_master(find_symbol_global, NULL, tbl, jmptbl, err); if (err->code) return 0; return 1; } +int flexdll_relocate(void *tbl) {return flexdll_relocate_v2(tbl, NULL);} + void set_env_ptr(char* name, void* ptr) { char env[256]; @@ -538,6 +562,7 @@ void *flexdll_wdlopen(const wchar_t *file, int mode) { if (!file) return &main_unit; set_env_ptr("FLEXDLL_RELOCATE", (exec ? &flexdll_relocate : 0)); + set_env_ptr("FLEXDLL_RELOCATE_V2", (exec ? &flexdll_relocate_v2 : 0)); again: if (units_mutex == INVALID_HANDLE_VALUE) { @@ -564,7 +589,7 @@ void *flexdll_wdlopen(const wchar_t *file, int mode) { else { unit = malloc(sizeof(dlunit)); unit->handle = handle; - unit->symtbl = ll_dlsym(handle, "symtbl"); + unit->symtbl = augment_symtbl(ll_dlsym(handle, "symtbl")); unit->count = 1; unit->global = 0; push_unit(unit); @@ -574,7 +599,7 @@ void *flexdll_wdlopen(const wchar_t *file, int mode) { if (exec) { /* Relocation has already been done if the flexdll's DLL entry point is used */ - flexdll_relocate(ll_dlsym(handle, "reloctbl")); + flexdll_relocate_v2(ll_dlsym(handle, "reloctbl"), ll_dlsym(handle, "jmptbl")); if (err->code) { flexdll_dlclose(unit); ReleaseMutex(units_mutex); return NULL; } } @@ -617,7 +642,7 @@ void flexdll_dlclose(void *u) { if (NULL == u || u == &main_unit) return; ll_dlclose(unit->handle); unit->count--; - if (unit->count == 0) { unlink_unit(unit); free(unit); } + if (unit->count == 0) { unlink_unit(unit); free(unit->symtbl); free(unit); } } @@ -632,7 +657,7 @@ void *flexdll_dlsym(void *u, const char *name) { return NULL; } if (u == &main_unit) res = find_symbol_global(NULL,name); - else if (NULL == u) res = find_symbol(&static_symtable,name); + else if (NULL == u) res = find_symbol(get_static_symtable(),name); else res = find_symbol(((dlunit*)u)->symtbl,name); ReleaseMutex(units_mutex); return (res ? res->addr : NULL); @@ -654,9 +679,9 @@ char *flexdll_dlerror(void) { void flexdll_dump_exports(void *u) { dlunit *unit = u; - if (NULL == u) { dump_symtbl(&static_symtable); } + if (NULL == u) { dump_symtbl(get_static_symtable()); } else if (u == &main_unit) { - dump_symtbl(&static_symtable); + dump_symtbl(get_static_symtable()); for (unit = units; unit; unit = unit->next) if (unit->global) { dump_symtbl(unit->symtbl); } } diff --git a/flexdll_initer.c b/flexdll_initer.c index 5f23dc6..2261aac 100644 --- a/flexdll_initer.c +++ b/flexdll_initer.c @@ -19,16 +19,27 @@ #include typedef int func(void*); +typedef int func_v2(void*,void*); extern int reloctbl; +extern int jmptbl; static int flexdll_init() { func *sym = 0; - char *s = getenv("FLEXDLL_RELOCATE"); - if (!s) { fprintf(stderr, "Cannot find FLEXDLL_RELOCATE\n"); return FALSE; } - sscanf(s,"%p",&sym); - /* sym = 0 means "loaded not for execution" */ - if (!sym || sym(&reloctbl)) return TRUE; + func_v2 *sym_v2 = 0; + char *s = getenv("FLEXDLL_RELOCATE_V2"); + /* If the supplied symbol is NULL, treat as "loaded not for execution" */ + if (!s) { + s = getenv("FLEXDLL_RELOCATE"); + if (!s) { fprintf(stderr, "Cannot find FLEXDLL_RELOCATE\n"); return FALSE; } + /* The executable image doesn't support the V2 interface, so RELOC_REL32 + may fail. */ + sscanf(s, "%p", &sym); + if (!sym || sym(&reloctbl)) return TRUE; + } else { + sscanf(s, "%p", &sym_v2); + if (!sym_v2 || sym_v2(&reloctbl, &jmptbl)) return TRUE; + } return FALSE; } From 4f461b77c9e840eba93ffba75b8c8a10593d14ee Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sun, 11 Feb 2018 13:37:57 +0000 Subject: [PATCH 06/15] Fix build on msvc64 --- flexdll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flexdll.c b/flexdll.c index 6e29e10..8f496d6 100644 --- a/flexdll.c +++ b/flexdll.c @@ -373,10 +373,10 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t void* trampoline = sym->trampoline = *jmptbl; /* movq $(sym->addr), %rax */ *((short*)trampoline) = 0xb848; - *((UINT_PTR*)(trampoline + 2)) = (UINT_PTR)sym->addr; + *((UINT_PTR*)((char*)trampoline + 2)) = (UINT_PTR)sym->addr; /* jmp %rax */ - *((short*)(trampoline + 10)) = 0xe0ff; - *jmptbl += 16; + *((short*)((char*)trampoline + 10)) = 0xe0ff; + *((char*)jmptbl) += 16; } s = (UINT_PTR)(sym->trampoline); s -= (INT_PTR)(ptr->addr) + rel_offset; From 64de60aeb53d6952a30949dee2629ccb6323a9a6 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sun, 11 Feb 2018 13:40:29 +0000 Subject: [PATCH 07/15] Can't use trampolines for data symbols. Verify that the page containing the target symbol is marked executable before creating a trampoline. --- flexdll.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/flexdll.c b/flexdll.c index 8f496d6..73753f2 100644 --- a/flexdll.c +++ b/flexdll.c @@ -272,6 +272,7 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t dynsymbol *sym; int rel_offset; char *reloc_type; + MEMORY_BASIC_INFORMATION info; if (!tbl) return; @@ -370,7 +371,15 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t if (s != (INT32) s) { if (jmptbl) { if (!sym->trampoline) { - void* trampoline = sym->trampoline = *jmptbl; + void* trampoline; + /* trampolines cannot be created for data */ + if (VirtualQuery(sym->addr, &info, sizeof(info)) && !(info.Protect & 0xf0)) { + sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far, and not executable: %p %p", + reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); + err->code = 3; + return; + } + trampoline = sym->trampoline = *jmptbl; /* movq $(sym->addr), %rax */ *((short*)trampoline) = 0xb848; *((UINT_PTR*)((char*)trampoline + 2)) = (UINT_PTR)sym->addr; From 909b57d4a6b808e88bc4db723ffd15f5e0eee4ba Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Wed, 14 Feb 2018 11:27:23 +0000 Subject: [PATCH 08/15] Use indirect jmp instead of trashing %rax --- flexdll.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/flexdll.c b/flexdll.c index 73753f2..29f95aa 100644 --- a/flexdll.c +++ b/flexdll.c @@ -380,11 +380,12 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t return; } trampoline = sym->trampoline = *jmptbl; - /* movq $(sym->addr), %rax */ - *((short*)trampoline) = 0xb848; - *((UINT_PTR*)((char*)trampoline + 2)) = (UINT_PTR)sym->addr; - /* jmp %rax */ - *((short*)((char*)trampoline + 10)) = 0xe0ff; + /* rex.W jmpq $0x0(%rip) */ + *((__int64*)trampoline) = 0x25ff48; + /* Place the actual symbol immediately after the instruction */ + *((UINT_PTR*)((char*)trampoline + 7)) = (UINT_PTR)sym->addr; + /* Pad with nop */ + *(((char*)trampoline + 15)) = 0x90; *((char*)jmptbl) += 16; } s = (UINT_PTR)(sym->trampoline); From 62dbeff57c1c70969bd0c3c8fa4c378a47ba5476 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Wed, 14 Feb 2018 14:46:29 +0000 Subject: [PATCH 09/15] Oh dear, oh dear, oh dear :$ --- flexdll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flexdll.c b/flexdll.c index 29f95aa..eb37479 100644 --- a/flexdll.c +++ b/flexdll.c @@ -386,7 +386,7 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t *((UINT_PTR*)((char*)trampoline + 7)) = (UINT_PTR)sym->addr; /* Pad with nop */ *(((char*)trampoline + 15)) = 0x90; - *((char*)jmptbl) += 16; + *((UINT_PTR*)jmptbl) += 16; } s = (UINT_PTR)(sym->trampoline); s -= (INT_PTR)(ptr->addr) + rel_offset; From e459fec4a0fcc38822b4baaf119ca2122ad585b7 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Wed, 14 Feb 2018 20:21:40 +0000 Subject: [PATCH 10/15] Create new trampolines when previous out of range Each unit has enough jmptbl space to be able to have trampolines for all of the symbols it imports. However, if two units load within 2GiB of each, the previous trampolines can be reused. Turns out that this is simpler than either resetting or storing multiple trampolines. --- flexdll.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/flexdll.c b/flexdll.c index eb37479..e34af5d 100644 --- a/flexdll.c +++ b/flexdll.c @@ -368,35 +368,39 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t if (rel_offset) s -= (INT_PTR)(ptr -> addr) + rel_offset; s += *((INT32*) ptr -> addr); +retry: if (s != (INT32) s) { - if (jmptbl) { - if (!sym->trampoline) { - void* trampoline; - /* trampolines cannot be created for data */ - if (VirtualQuery(sym->addr, &info, sizeof(info)) && !(info.Protect & 0xf0)) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far, and not executable: %p %p", - reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); - err->code = 3; - return; - } - trampoline = sym->trampoline = *jmptbl; - /* rex.W jmpq $0x0(%rip) */ - *((__int64*)trampoline) = 0x25ff48; - /* Place the actual symbol immediately after the instruction */ - *((UINT_PTR*)((char*)trampoline + 7)) = (UINT_PTR)sym->addr; - /* Pad with nop */ - *(((char*)trampoline + 15)) = 0x90; - *((UINT_PTR*)jmptbl) += 16; - } - s = (UINT_PTR)(sym->trampoline); - s -= (INT_PTR)(ptr->addr) + rel_offset; - s += *((INT32*)ptr->addr); - } else { + if (!jmptbl) { sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far: %p %p", reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); err->code = 3; return; } + if (!sym->trampoline) { + void* trampoline; + /* trampolines cannot be created for data */ + if (VirtualQuery(sym->addr, &info, sizeof(info)) && !(info.Protect & 0xf0)) { + sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far, and not executable: %p %p", + reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); + err->code = 3; + return; + } + trampoline = sym->trampoline = *jmptbl; + /* rex.W jmpq $0x0(%rip) */ + *((__int64*)trampoline) = 0x25ff48; + /* Place the actual symbol immediately after the instruction */ + *((UINT_PTR*)((char*)trampoline + 7)) = (UINT_PTR)sym->addr; + /* Pad with nop */ + *(((char*)trampoline + 15)) = 0x90; + *((UINT_PTR*)jmptbl) += 16; + } + s = (UINT_PTR)(sym->trampoline); + s -= (INT_PTR)(ptr->addr) + rel_offset; + s += *((INT32*)ptr->addr); + } + if (s != (INT32)s) { + sym->trampoline = NULL; + goto retry; } *((UINT32*) ptr->addr) = (INT32)s; } From afc232f3df226fb740c2374ed3a881ce4d52d03e Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Thu, 15 Feb 2018 10:07:31 +0000 Subject: [PATCH 11/15] Test everything on AppVeyor for SKIP_OCAML_TEST=no --- appveyor_build.sh | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/appveyor_build.sh b/appveyor_build.sh index 003ae31..65f74ae 100755 --- a/appveyor_build.sh +++ b/appveyor_build.sh @@ -24,24 +24,32 @@ function configure_ocaml { sed -i -e 's/@iflexdir@/-I"$(ROOTDIR)\/flexdll"/' Makefile.config.in fi + if [ "$1" = "full" ] ; then + DISABLE=() + else + DISABLE=(--disable-debugger \ + --disable-ocamldoc \ + --disable-systhreads \ + --disable-str-lib \ + --disable-unix-lib \ + --disable-bigarray-lib \ + $GRAPHICS_DISABLE \ + $OCAMLTEST_DISABLE \ + --disable-debug-runtime) + fi ./configure --build=x86_64-pc-cygwin --host=$OCAML_TARGET \ - --prefix=$OCAMLROOT \ - --disable-debugger \ - --disable-ocamldoc \ - --disable-systhreads \ - --disable-str-lib \ - --disable-unix-lib \ - --disable-bigarray-lib \ - $GRAPHICS_DISABLE \ - $OCAMLTEST_DISABLE \ - --disable-debug-runtime + --prefix=$OCAMLROOT "${DISABLE[@]}" else # "Classic" configuration cp config/m-nt.h $HEADER_DIR/m.h cp config/s-nt.h $HEADER_DIR/s.h - sed -e "s|PREFIX=.*|PREFIX=$OCAMLROOT|" \ - -e 's/\(OTHERLIBRARIES\|WITH_DEBUGGER\|WITH_OCAMLDOC\|DEBUGGER\|EXTRALIBS\|WITH_OCAMLBUILD\|CAMLP4\)=.*/\1=/' \ + if [ "$1" = "full" ] ; then + DISABLE=() + else + DISABLE=(-e 's/\(OTHERLIBRARIES\|WITH_OCAMLDOC\|WITH_DEBUGGER\|DEBUGGER\|EXTRALIBS\|WITH_OCAMLBUILD\|CAMLP4\)=.*/\1=/') + fi + sed -e "s|PREFIX=.*|PREFIX=$OCAMLROOT|" "${DISABLE[@]}" \ config/Makefile.$OCAML_PORT > $CONFIG_DIR/Makefile #run "Content of config/Makefile" cat $CONFIG_DIR/Makefile fi @@ -196,7 +204,7 @@ done popd if [ "$SKIP_OCAML_TEST" = no ] ; then - configure_ocaml + configure_ocaml full cd flexdll git remote add local $(echo "$APPVEYOR_BUILD_FOLDER"| cygpath -f -) -f --tags From db30ffe673bfe350be4ecd6b4a216737576f3f84 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Thu, 15 Feb 2018 09:36:13 +0000 Subject: [PATCH 12/15] Test large RELOC_REL32 on AppVeyor --- appveyor_build.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/appveyor_build.sh b/appveyor_build.sh index 65f74ae..3195c97 100755 --- a/appveyor_build.sh +++ b/appveyor_build.sh @@ -206,6 +206,16 @@ popd if [ "$SKIP_OCAML_TEST" = no ] ; then configure_ocaml full + if [[ -e otherlibs/win32unix/Makefile ]]; then + unix_dir='win32' + else + unix_dir='' + fi + # This tortures the ocamldoc compilation as it means that dllcamlstr, + # dllunix and ocamlrun will all be more than 2GiB apart. + sed -i -e "s/^LDOPTS=.*/\0 -ldopt -base -ldopt 0x210000000/" "otherlibs/${unix_dir}unix/Makefile" + sed -i -e "/^include \.\.\/Makefile/aLDOPTS=-ldopt -base -ldopt 0x310000000" otherlibs/str/Makefile + cd flexdll git remote add local $(echo "$APPVEYOR_BUILD_FOLDER"| cygpath -f -) -f --tags run "git checkout $APPVEYOR_REPO_COMMIT" git checkout merge From 9ce19d275cf936b609850aabbde2835dade2ce7a Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Thu, 15 Feb 2018 11:17:21 +0000 Subject: [PATCH 13/15] Don't generate jmptbl symbol on 32-bit --- flexdll_initer.c | 12 +++++++++++- reloc.ml | 18 ++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/flexdll_initer.c b/flexdll_initer.c index 2261aac..4d57c0b 100644 --- a/flexdll_initer.c +++ b/flexdll_initer.c @@ -22,24 +22,34 @@ typedef int func(void*); typedef int func_v2(void*,void*); extern int reloctbl; +#if defined(_WIN64) || defined(__CYGWIN64__) extern int jmptbl; +#endif static int flexdll_init() { func *sym = 0; +#if defined(_WIN64) || defined(__CYGWIN64) func_v2 *sym_v2 = 0; - char *s = getenv("FLEXDLL_RELOCATE_V2"); +#endif /* If the supplied symbol is NULL, treat as "loaded not for execution" */ +#if defined(_WIN64) || defined(__CYGWIN64) + char *s = getenv("FLEXDLL_RELOCATE_V2"); if (!s) { +#else + char *s; +#endif s = getenv("FLEXDLL_RELOCATE"); if (!s) { fprintf(stderr, "Cannot find FLEXDLL_RELOCATE\n"); return FALSE; } /* The executable image doesn't support the V2 interface, so RELOC_REL32 may fail. */ sscanf(s, "%p", &sym); if (!sym || sym(&reloctbl)) return TRUE; +#if defined(_WIN64) || defined(__CYGWIN64) } else { sscanf(s, "%p", &sym_v2); if (!sym_v2 || sym_v2(&reloctbl, &jmptbl)) return TRUE; } +#endif return FALSE; } diff --git a/reloc.ml b/reloc.ml index b2e6f5e..74fb613 100644 --- a/reloc.ml +++ b/reloc.ml @@ -858,7 +858,7 @@ let build_dll link_exe output_file files exts extra_args = List.iter (fun fn -> collect_file (find_file fn)) exts; if main_pgm then add_def (usym "static_symtable") - else (add_def (usym "reloctbl"); add_def (usym "jmptbl")); + else (add_def (usym "reloctbl"); if !machine = `x64 then add_def (usym "jmptbl")); if !machine = `x64 then add_def "__ImageBase" else add_def "___ImageBase"; @@ -1045,7 +1045,8 @@ let build_dll link_exe output_file files exts extra_args = (usym (if main_pgm then "static_symtable" else "symtbl")); if not main_pgm then begin add_master_reloc_table obj !reloctbls (usym "reloctbl"); - add_master_jmp_table obj !trampolines (usym "jmptbl"); + if !machine = `x64 then + add_master_jmp_table obj !trampolines (usym "jmptbl"); end; if !errors then @@ -1147,10 +1148,11 @@ let build_dll link_exe output_file files exts extra_args = with the Windows 7 SDK in 64-bit mode. *) Printf.sprintf - "link /nologo %s%s%s%s%s /implib:%s /out:%s /subsystem:%s %s %s %s" + "link /nologo %s%s%s%s%s%s /implib:%s /out:%s /subsystem:%s %s %s %s" (if !verbose >= 2 then "/verbose " else "") (if link_exe = `EXE then "" else "/dll ") - (if main_pgm then "" else "/export:symtbl /export:reloctbl /export:jmptbl ") + (if main_pgm then "" else "/export:symtbl /export:reloctbl ") + (if main_pgm || !machine = `x86 then "" else "/export:jmptbl ") (if main_pgm then "" else if !noentry then "/noentry " else let s = match !machine with @@ -1170,7 +1172,9 @@ let build_dll link_exe output_file files exts extra_args = if main_pgm then "" else let def_file, oc = open_temp_file "flexlink" ".def" in - Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n jmptbl\n"; + Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n"; + if !machine = `x64 then + Printf.fprintf oc " jmptbl\n"; close_out oc; Filename.quote def_file in @@ -1196,7 +1200,9 @@ let build_dll link_exe output_file files exts extra_args = if main_pgm then "" else let def_file, oc = open_temp_file "flexlink" ".def" in - Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n jmptbl\n"; + Printf.fprintf oc "EXPORTS\n reloctbl\n symtbl\n"; + if !machine = `x64 then + Printf.fprintf oc " jmptbl\n"; close_out oc; Filename.quote def_file in From 20599e379950f73f5e3bb3e6d7f7f9ae56bd800f Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Thu, 15 Feb 2018 12:17:03 +0000 Subject: [PATCH 14/15] Prevent local OCaml from interfering on AppVeyor The wrong DLLs can end up being loaded while building OCaml :-/ --- appveyor_build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor_build.sh b/appveyor_build.sh index 3195c97..1592217 100755 --- a/appveyor_build.sh +++ b/appveyor_build.sh @@ -221,7 +221,9 @@ if [ "$SKIP_OCAML_TEST" = no ] ; then run "git checkout $APPVEYOR_REPO_COMMIT" git checkout merge cd .. + mv $OCAMLROOT $OCAMLROOT-Disabled run "make world" $MAKEOCAML flexdll world + mv $OCAMLROOT-Disabled $OCAMLROOT fi if [ "$ARTEFACTS" = 'yes' ] ; then From 3dc05ee387fcdc190191f9fe00cca2560b1dfab9 Mon Sep 17 00:00:00 2001 From: David Allsopp Date: Sun, 25 Feb 2018 10:41:09 +0000 Subject: [PATCH 15/15] WIP: Include symbol name in relocation error Need some kind of check on the length of ptr->name (cf. cannot_resolve_msg) --- flexdll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flexdll.c b/flexdll.c index e34af5d..ac5d24c 100644 --- a/flexdll.c +++ b/flexdll.c @@ -371,8 +371,8 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t retry: if (s != (INT32) s) { if (!jmptbl) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far: %p %p", - reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); + sprintf(err->message, "flexdll error: cannot relocate %s RELOC_%s, target is too far: %p %p", + ptr->name, reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); err->code = 3; return; } @@ -380,8 +380,8 @@ static void relocate(resolver f, void *data, reloctbl *tbl, void **jmptbl, err_t void* trampoline; /* trampolines cannot be created for data */ if (VirtualQuery(sym->addr, &info, sizeof(info)) && !(info.Protect & 0xf0)) { - sprintf(err->message, "flexdll error: cannot relocate RELOC_%s, target is too far, and not executable: %p %p", - reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); + sprintf(err->message, "flexdll error: cannot relocate %s RELOC_%s, target is too far, and not executable: %p %p", + ptr->name, reloc_type, (void *)((UINT_PTR) s), (void *) ((UINT_PTR)(INT32) s)); err->code = 3; return; }