Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support relocation kind 0003 and extend IMAGE_REL_ types #141

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
jonahbeckford marked this conversation as resolved.
Show resolved Hide resolved

```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

Expand Down
34 changes: 24 additions & 10 deletions flexdll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
20 changes: 15 additions & 5 deletions reloc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 *) ->
Expand All @@ -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*) ) ->
Expand Down