From 19aadf0b656b9785ce84c5e00582279dd0e02622 Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Sun, 28 Jul 2024 13:05:19 -0700 Subject: [PATCH 1/5] Support relocation kind 0003 and extend IMAGE_REL_ types. Specifically adds support for: - IMAGE_REL_AMD64_ADDR32NB. (This is the "relocation kind 0003"). - IMAGE_REL_I386_DIR32NB. (This is the x86 version of the above). - IMAGE_REL_AMD64_REL32_5. (This is documented but weirdly not implemented). --- CHANGES | 3 ++- flexdll.c | 21 +++++++++++++++++++++ reloc.ml | 5 +++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index da6c1b6..22f86c1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,8 @@ Next version - 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 + IMAGE_REL_I386_DIR32NB. Extend relative types to IMAGE_REL_AMD64_REL32_5. (Jonah Beckford) Version 0.43 - GPR#108: Add -lgcc_s to Cygwin's link libraries, upstreaming a patch from the diff --git a/flexdll.c b/flexdll.c index 72a08c5..33b7264 100644 --- a/flexdll.c +++ b/flexdll.c @@ -31,6 +31,8 @@ typedef unsigned long uintnat; #define RELOC_REL32_4 0x0003 #define RELOC_REL32_1 0x0004 #define RELOC_REL32_2 0x0005 +#define RELOC_REL32_5 0x0006 +#define RELOC_32NB 0x0007 #define RELOC_DONE 0x0100 typedef struct { UINT_PTR kind; char *name; UINT_PTR *addr; } reloc_entry; @@ -356,6 +358,25 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { } *((UINT32*) ptr->addr) = (INT32) s; 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) = s; + 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) = s; + break; default: fprintf(stderr, "flexdll: unknown relocation kind"); exit(2); diff --git a/reloc.ml b/reloc.ml index 93a8d7f..67e84c0 100644 --- a/reloc.ml +++ b/reloc.ml @@ -433,6 +433,10 @@ let add_reloc_table obj obj_name p = | `x64, 0x01 (* IMAGE_REL_AMD64_ADDR64 *) -> 0x0002 (* absolute, native size (32/64) *) + | `x86, 0x07 (* IMAGE_REL_I386_DIR32NB *) + | `x64, 0x03 (* IMAGE_REL_AMD64_ADDR32NB *) -> + 0x0007 (* 32nb *) + | `x64, 0x04 (* IMAGE_REL_AMD64_REL32 *) | `x86, 0x14 (* IMAGE_REL_I386_REL32 *) when not !no_rel_relocs -> 0x0001 (* rel32 *) @@ -440,6 +444,7 @@ let add_reloc_table obj obj_name p = | `x64, 0x05 when not !no_rel_relocs -> 0x0004 (* rel32_1 *) | `x64, 0x08 when not !no_rel_relocs-> 0x0003 (* rel32_4 *) | `x64, 0x06 when not !no_rel_relocs-> 0x0005 (* rel32_2 *) + | `x64, 0x09 when not !no_rel_relocs-> 0x0006 (* rel32_5 *) | (`x86 | `x64), (0x0a (* IMAGE_REL_{I386|AMD64}_SECTION *) | 0x0b (* IMAGE_REL_{I386|AMD64}_SECREL*) ) -> From b346f56bf8ae84300934d45a16d1c922c9b4db7a Mon Sep 17 00:00:00 2001 From: jonahbeckford <71855677+jonahbeckford@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:16:49 -0700 Subject: [PATCH 2/5] Avoid conversion from 'INT_PTR' to 'UINT32' warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Antonin Décimo --- flexdll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flexdll.c b/flexdll.c index 33b7264..8c8d039 100644 --- a/flexdll.c +++ b/flexdll.c @@ -366,7 +366,7 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { err->code = 3; goto restore; } - *((UINT32*) ptr->addr) = s; + *((UINT32*) ptr->addr) = (INT32) s; break; case RELOC_32NB: s += *((INT32*) ptr -> addr); @@ -375,7 +375,7 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { err->code = 3; goto restore; } - *((UINT32*) ptr->addr) = s; + *((UINT32*) ptr->addr) = (INT32) s; break; default: fprintf(stderr, "flexdll: unknown relocation kind"); From 275b310721c17b108c9aa5cd1d951cbb2f4976e9 Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Tue, 26 Nov 2024 13:51:55 -0800 Subject: [PATCH 3/5] Add RELOC_REL32_4 Also reorder match (OCaml) and case (C) for clarity and to ensure nothing is missed. --- flexdll.c | 34 ++++++++++++++++++++++++---------- reloc.ml | 20 +++++++++++++++----- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/flexdll.c b/flexdll.c index 8c8d039..edada97 100644 --- a/flexdll.c +++ b/flexdll.c @@ -26,11 +26,15 @@ typedef long intnat; typedef unsigned long uintnat; +/* RELOC_ constants except RELOC_DONE have ordinal values based on when + they were introduced to the code base. These ordinal values are + persisted in .obj files so do not re-use any existing ordinals. */ #define RELOC_REL32 0x0001 #define RELOC_ABS 0x0002 -#define RELOC_REL32_4 0x0003 #define RELOC_REL32_1 0x0004 #define RELOC_REL32_2 0x0005 +#define RELOC_REL32_3 0x0008 +#define RELOC_REL32_4 0x0003 #define RELOC_REL32_5 0x0006 #define RELOC_32NB 0x0007 #define RELOC_DONE 0x0100 @@ -328,31 +332,41 @@ static void relocate(resolver f, void *data, reloctbl *tbl, err_t *err) { } *((UINT32*) ptr->addr) = (INT32) s; break; - case RELOC_REL32_4: - s -= (INT_PTR)(ptr -> addr) + 8; + 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_4, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(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; break; - case RELOC_REL32_1: - s -= (INT_PTR)(ptr -> addr) + 5; + 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_1, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(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; break; - case RELOC_REL32_2: - s -= (INT_PTR)(ptr -> addr) + 6; + 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_2, target is too far: %p %p",(void *)((UINT_PTR) s), (void *) ((UINT_PTR)(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; + 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; } diff --git a/reloc.ml b/reloc.ml index 67e84c0..9b3c8ca 100644 --- a/reloc.ml +++ b/reloc.ml @@ -427,7 +427,11 @@ let add_reloc_table obj obj_name p = let syms = ref [] in let reloc secsym min max rel = if p rel.symbol then ( - (* kind *) + (* kind = f(machine,rtype) + - a RELOC_ constant in flexdll.c + + rtype + - https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#x64-processors *) let kind = match !machine, rel.rtype with | `x86, 0x06 (* IMAGE_REL_I386_DIR32 *) | `x64, 0x01 (* IMAGE_REL_AMD64_ADDR64 *) -> @@ -441,10 +445,16 @@ let add_reloc_table obj obj_name p = | `x86, 0x14 (* IMAGE_REL_I386_REL32 *) when not !no_rel_relocs -> 0x0001 (* rel32 *) - | `x64, 0x05 when not !no_rel_relocs -> 0x0004 (* rel32_1 *) - | `x64, 0x08 when not !no_rel_relocs-> 0x0003 (* rel32_4 *) - | `x64, 0x06 when not !no_rel_relocs-> 0x0005 (* rel32_2 *) - | `x64, 0x09 when not !no_rel_relocs-> 0x0006 (* rel32_5 *) + | `x64, 0x05 (* IMAGE_REL_AMD64_REL32_1 *) when not !no_rel_relocs-> + 0x0004 (* rel32_1 *) + | `x64, 0x06 (* IMAGE_REL_AMD64_REL32_2 *) when not !no_rel_relocs-> + 0x0005 (* rel32_2 *) + | `x64, 0x07 (* IMAGE_REL_AMD64_REL32_3 *) when not !no_rel_relocs-> + 0x0008 (* rel32_3 *) + | `x64, 0x08 (* IMAGE_REL_AMD64_REL32_4 *) when not !no_rel_relocs-> + 0x0003 (* rel32_4 *) + | `x64, 0x09 (* IMAGE_REL_AMD64_REL32_5 *) when not !no_rel_relocs-> + 0x0006 (* rel32_5 *) | (`x86 | `x64), (0x0a (* IMAGE_REL_{I386|AMD64}_SECTION *) | 0x0b (* IMAGE_REL_{I386|AMD64}_SECREL*) ) -> From 5b09bd61c1c62cdd8ae4ad3fff4be16c6df1c746 Mon Sep 17 00:00:00 2001 From: Jonah Beckford <9566106-jonahbeckford@users.noreply.gitlab.com> Date: Tue, 26 Nov 2024 14:05:53 -0800 Subject: [PATCH 4/5] Improve __declspec(dllimport) doc --- README.md | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a7adab4..468f7ec 100644 --- a/README.md +++ b/README.md @@ -371,11 +371,43 @@ Note that you can define and use the `_imp__XXX` symbols by hand, you don't have to use the `__declspec(dllimport)` notation (this is useful if you use a compiler that doesn't support this notation). -Anyway, there is no compelling reason for adopting this style. A very -small advantage might be that there will be fewer relocations at runtime -and that more code pages can be shared amongst several instances of the -same DLL used by different processes. +There *are* compelling reasons to adopt this style. +A very small advantage might be that there will be fewer relocations at +runtime and that more code pages can be shared amongst several instances +of the same DLL used by different processes. + +A big advantage on IA-64 systems is to avoid relocation errors like: + +```text +Fatal error: cannot load shared library plug1 +Reason: flexdll error: cannot relocate XXX + RELOC_REL32, target is too far: FFFFFFFF2EDEC956 000000002EDEC956 +``` + +Without `__declspec(dllimport)` your symbol (ex. `extern XXX`) generates +the following pseudo-assembly: + +```asm +CALL XXX ; this is a 32-bit relative address +``` + +These 32-bit relative addresses are restricted to 2GiB jumps, and there is +no guarantee that your main programs and all its DLLs will reside in the same +2GiB block of virtual memory. The more DLLs you have, and the bigger they +are, the more likely you will encounter a `RELOC_REL32` error. + +flexdll will verify every 32-bit relative address `CALL` during +`flexdll_dlopen` to ensure they are within 2GiB. +However, the indirection introduced by `__declspec(dllimport) extern` makes +the pseudo-assembly instead: + +```asm +void *_imp__XXX = &XXX; +CALL [_imp__XXX] ; this is a 64-bit indirect address +``` + +which works well with flexdll. ## Advanced topic: static constructors and the entry point From 3b4624063855a14dfc082f5937e7079632865f5f Mon Sep 17 00:00:00 2001 From: jonahbeckford <71855677+jonahbeckford@users.noreply.github.com> Date: Thu, 28 Nov 2024 08:25:57 -0800 Subject: [PATCH 5/5] Update README.md to say x86_64 Co-authored-by: David Allsopp --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 468f7ec..45b62a9 100644 --- a/README.md +++ b/README.md @@ -377,7 +377,7 @@ A very small advantage might be that there will be fewer relocations at runtime and that more code pages can be shared amongst several instances of the same DLL used by different processes. -A big advantage on IA-64 systems is to avoid relocation errors like: +A big advantage on x86_64 systems is to avoid relocation errors like: ```text Fatal error: cannot load shared library plug1