An --x86 host reloads an --x86 module, checked by running it
This commit is contained in:
parent
69ea66deca
commit
bd69f684ed
26
lib/x86.ml
26
lib/x86.ml
@ -611,9 +611,8 @@ let addr_into f ~reg (l : loc) =
|
||||
load_int f.b ~dst:reg ~mm:(Frame p) ~size:8 ~signed:false;
|
||||
if a <> 0 then add_imm f.b ~dst:reg a
|
||||
|
||||
(* The three spellings of "name a symbol", each picking the pc-relative form
|
||||
(* The spellings of "name a symbol", each picking the pc-relative form
|
||||
for a symbol this object defines and the GOT form for one it does not. *)
|
||||
let sym_mem f s = if f.ext s then Got s else Sym (s, 0)
|
||||
let sym_loc f s = if f.ext s then Lgot (s, 0) else Lg (s, 0)
|
||||
|
||||
(* [lea] of a symbol is an address; out of the GOT the address is already
|
||||
@ -622,6 +621,19 @@ let addr_sym f ~dst s =
|
||||
if f.ext s then load_int f.b ~dst ~mm:(Got s) ~size:8 ~signed:false
|
||||
else lea f.b ~dst ~mm:(Sym (s, 0))
|
||||
|
||||
(* Read what a global holds, as opposed to where it is -- an indirection cell
|
||||
is the only caller. Out of the GOT that is two loads, not one: the slot
|
||||
holds the cell's *address*. Collapsing them was this lane's one real bug,
|
||||
and it looked exactly right in the disassembly: [mov r11, cell@GOTPCREL(%rip)]
|
||||
beside [call *%r11] reads as "call through the cell" and in fact calls the
|
||||
cell. DISCUSS.md item 15 said this is how hand-encoding fails. *)
|
||||
let load_sym f ~dst s =
|
||||
if f.ext s then begin
|
||||
load_int f.b ~dst ~mm:(Got s) ~size:8 ~signed:false;
|
||||
load_int f.b ~dst ~mm:(Reg (dst, 0)) ~size:8 ~signed:false
|
||||
end
|
||||
else load_int f.b ~dst ~mm:(Sym (s, 0)) ~size:8 ~signed:false
|
||||
|
||||
let scalar_size f (t : Types.t) =
|
||||
match t with Types.Bool -> 1 | _ -> max 1 (sizeof f.md t)
|
||||
|
||||
@ -1005,7 +1017,7 @@ and lower_at f (e : Tast.expr) (dst : loc) : unit =
|
||||
address is in a slot there is nothing left to re-resolve. *)
|
||||
| Tast.FnAddr (Tast.Fnval n) ->
|
||||
if f.md.Emit.dev then
|
||||
load_int f.b ~dst:rax ~mm:(sym_mem f (csym n)) ~size:8 ~signed:false
|
||||
load_sym f ~dst:rax (csym n)
|
||||
else addr_sym f ~dst:rax (fsym n);
|
||||
store_int f.b ~src:rax ~mm:(lmem f dst ~scratch:r11) ~size:8
|
||||
| Tast.FnAddr (Tast.Rtfn n) ->
|
||||
@ -1816,7 +1828,7 @@ and call_flan f ~target ~args ~rty dst =
|
||||
(match callee with
|
||||
| `Sym s -> call_sym f.b s
|
||||
| `Cell s ->
|
||||
load_int f.b ~dst:r11 ~mm:(sym_mem f s) ~size:8 ~signed:false;
|
||||
load_sym f ~dst:r11 s;
|
||||
call_r f.b r11
|
||||
| `Loc o ->
|
||||
load_int f.b ~dst:r11 ~mm:(Frame o) ~size:8 ~signed:false;
|
||||
@ -2607,7 +2619,11 @@ let program ~checks ?(dev = false) (p : Tast.program) : string =
|
||||
Buffer.add_string rodata gr;
|
||||
(match List.find_opt (fun (f : Tast.fn) -> f.Tast.name = "main") p.Tast.fns with
|
||||
| Some fn -> Buffer.add_string text (emit_main md fn)
|
||||
| None -> unsupported "no main");
|
||||
(* No [main] is not an error, and [emit.ml] treats it the same way: a
|
||||
program can be linked against a C host that brings its own entry point,
|
||||
which is what [reload_host.c] is. Refusing here made a --x86 host for the
|
||||
reload tests impossible to build. *)
|
||||
| None -> ());
|
||||
let out = Buffer.create 65536 in
|
||||
Buffer.add_buffer out text;
|
||||
(* The globals' initialiser runs before main, through the same constructor
|
||||
|
||||
@ -200,6 +200,58 @@ let () =
|
||||
if code <> 0 || text <> want then
|
||||
fail "reload\n got: %S (exit %d)\n wanted: %S" text code want;
|
||||
|
||||
(* The same thing again, compiled by the dev backend end to end (x86.ml's
|
||||
header, HANDOFF-x86-rt.md item 1). Both halves, host and module, because
|
||||
the two backends' conventions agree on every scalar and disagree on
|
||||
every aggregate: an LLVM-built module dlopened into an --x86 host would
|
||||
be correct until the first redefined function took or returned a struct.
|
||||
So an --x86 host gets --x86 modules and the two never meet.
|
||||
|
||||
Only v1 and v2, which is the whole of what X86.redefinition compiles:
|
||||
every name they touch is one the host was built with. v3 and v4
|
||||
introduce a function and a global at run time, and the flan_dev_cell /
|
||||
flan_dev_global lookups that needs are refused there by name.
|
||||
|
||||
Read by running, not by reading. A disassembly reads correctly beside a
|
||||
wrong answer often enough (DISCUSS.md item 15) that only the printed
|
||||
transcript settles it: [outer] is compiled once into the host and never
|
||||
rebuilt, so "after2 1204" can only mean its call site followed a body
|
||||
that this backend emitted, published through a cell it reached via the
|
||||
GOT. *)
|
||||
let x86 = { dev with Build.x86 = true } in
|
||||
let xhost = tmp "xhost" in
|
||||
ignore
|
||||
(Build.executable ~opts:x86 ~csrcs:[ "reload_host.c" ]
|
||||
~lflags:[ "-ldl" ] p1 ~out:xhost);
|
||||
let xmodule q fns name =
|
||||
let o = tmp name in
|
||||
let asm = X86.redefinition ~checks:true ~dev:true ~known q ~fns in
|
||||
ignore (Build.shared_x86 ~opts:x86 ~asm ~out:o ());
|
||||
o
|
||||
in
|
||||
let xso1 = xmodule p1 [ "bump" ] "xv1.so" in
|
||||
let xso2 = xmodule p2 [ "bump" ] "xv2.so" in
|
||||
let xout = tmp "xout" in
|
||||
let xcode =
|
||||
Sys.command
|
||||
(Printf.sprintf "%s %s %s > %s 2> %s" (Filename.quote xhost)
|
||||
(Filename.quote xso1) (Filename.quote xso2) (Filename.quote xout)
|
||||
(Filename.quote (tmp "xerr")))
|
||||
in
|
||||
let xtext = In_channel.with_open_bin xout In_channel.input_all in
|
||||
let xwant =
|
||||
"v1\nhost 2\nv1\nafter1 4\n" ^ v2s ^ "after2 1204\ncounter 102\n"
|
||||
in
|
||||
if xcode <> 0 || xtext <> xwant then
|
||||
fail "x86 reload\n got: %S (exit %d)\n wanted: %S" xtext xcode
|
||||
xwant;
|
||||
(* A name the host was never built with has no symbol to bind to, and the
|
||||
registry path is not built here. It has to refuse rather than emit
|
||||
something that links and then stores through a null. *)
|
||||
(match X86.redefinition ~checks:true ~dev:true ~known p3 ~fns:[ "added" ] with
|
||||
| _ -> fail "x86 redefinition accepted a name the host does not have"
|
||||
| exception X86.Unsupported _ -> ());
|
||||
|
||||
(* The layout-drift guard, which needs a process of its own because what it
|
||||
does is abort one. [extra] does not exist in the host: v3 introduced it
|
||||
at run time, so flan_dev.c allocated its storage and recorded its size,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user