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 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion CHANGES
Original file line number Diff line number Diff line change
@@ -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
Expand Down
21 changes: 21 additions & 0 deletions flexdll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Copy link
Collaborator

@nojb nojb Jul 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my own understanding:

  • In LLVM, this relocation is implemented by add32(off, s), so that off in LLVM corresponds to ptr->addr in Flexlink and s in LLVM corresponds to s in Flexlink.
  • The relocation IMAGE_REL_AMD64_ADDR64 in LLVM (RELOC_ABS in Flexlink) is implemented by add64(off, s + imageBase), so that s + imageBase in LLVM corresponds to s in Flexlink.

Do you understand why the s arguments do not seem to match between the two cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going one step further, those equations imply that imageBase = 0.

I spent a lot of time looking and I couldn't find out why IMAGE_REL_AMD64_ADDR64 seems to work. The math for all the other relocation kinds make sense.

However, two things ...

  1. The /base: base address link.exe option is fixed for OCaml executable to be 0x10000 at
    let base_addr = ref "0x10000"

    and also the same in
    let image_base = 0x10000l in

    for OCaml plugins / stubs.
  2. All of the relative relocations from this section of code are translated by:

    flexdll/reloc.ml

    Lines 470 to 475 in 80496b5

    Reloc.abs !machine sect (Int32.of_int (Buffer.length data)) strsym;
    int_to_buf data pos;
    Reloc.abs !machine sect (Int32.of_int (Buffer.length data))
    (Lazy.force secsym);
    int_to_buf data (Int32.to_int rel.addr);

    into absolute relocations by Reloc.abs:

    flexdll/coff.ml

    Lines 437 to 444 in 80496b5

    module Reloc = struct
    let abs machine sec addr sym =
    let rtype =
    match machine with
    | `x86 -> 0x06
    | `x64 -> 0x01
    in
    sec.relocs <- { addr = addr; symbol = sym; rtype = rtype } :: sec.relocs

So my suspicion was that the Reloc.abs absolute relocations were being translated at CreateProcess time by ntdll.LdrInitializeThunk (or whatever is reading the PE .reloc section) to complete the imageBase adjustment.

@dra27, any chance you can explain why base_addr (or image_base for DLLs) is not used in the calculations?

(These calculations are undocumented in flexdll and fairly complicated)

break;
default:
fprintf(stderr, "flexdll: unknown relocation kind");
exit(2);
Expand Down
5 changes: 5 additions & 0 deletions reloc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -433,13 +433,18 @@ 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 *)

| `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*) ) ->
Expand Down