1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
(*
* machine-specific assembler routines.
*)
open Common;;
type asm_glue =
{
asm_activate_glue : Llvm.llvalue;
asm_yield_glue : Llvm.llvalue;
asm_upcall_glues : Llvm.llvalue array;
}
;;
let n_upcall_glues = 7
;;
(* x86-specific asm. *)
let x86_glue
(llctx:Llvm.llcontext)
(llmod:Llvm.llmodule)
(abi:Llabi.abi)
(sess:Session.sess)
: asm_glue =
let (prefix,align) =
match sess.Session.sess_targ with
Linux_x86_elf -> ("", 4)
| Win32_x86_pe -> ("_",4)
| MacOS_x86_macho -> ("_", 16)
in
let save_callee_saves =
["pushl %ebp";
"pushl %edi";
"pushl %esi";
"pushl %ebx";]
in
let restore_callee_saves =
["popl %ebx";
"popl %esi";
"popl %edi";
"popl %ebp";]
in
let load_esp_from_rust_sp =
[ Printf.sprintf "movl %d(%%edx), %%esp"
(Abi.task_field_rust_sp * 4)]
in
let load_esp_from_runtime_sp =
[ Printf.sprintf "movl %d(%%edx), %%esp"
(Abi.task_field_runtime_sp * 4) ]
in
let store_esp_to_rust_sp =
[ Printf.sprintf "movl %%esp, %d(%%edx)"
(Abi.task_field_rust_sp * 4) ]
in
let store_esp_to_runtime_sp =
[ Printf.sprintf "movl %%esp, %d(%%edx)"
(Abi.task_field_runtime_sp * 4) ]
in
let list_init i f = (Array.to_list (Array.init i f)) in
let list_init_concat i f = List.concat (list_init i f) in
let glue =
[
("rust_activate_glue",
String.concat "\n\t"
(["movl 4(%esp), %edx # edx = rust_task"]
@ save_callee_saves
@ store_esp_to_runtime_sp
@ load_esp_from_rust_sp
(*
* This 'add' instruction is a bit surprising.
* See lengthy comment in boot/be/x86.ml activate_glue.
*)
@ [ Printf.sprintf
"addl $20, %d(%%edx)"
(Abi.task_field_rust_sp * 4) ]
@ restore_callee_saves
@ ["ret"]));
("rust_yield_glue",
String.concat "\n\t"
(["movl 0(%esp), %edx # edx = rust_task"]
@ load_esp_from_rust_sp
@ save_callee_saves
@ store_esp_to_rust_sp
@ load_esp_from_runtime_sp
@ restore_callee_saves
@ ["ret"]))
]
@ list_init n_upcall_glues
begin
fun i ->
(*
* 0, 4, 8, 12 are callee-saves
* 16 is retpc
* 20 is taskptr
* 24 is callee
* 28 .. (7+i) * 4 are args
*)
((Printf.sprintf "rust_upcall_%d" i),
String.concat "\n\t"
(save_callee_saves
@ ["movl %esp, %ebp # ebp = rust_sp";
"movl 20(%esp), %edx # edx = rust_task"]
@ store_esp_to_rust_sp
@ load_esp_from_runtime_sp
@ [Printf.sprintf
"subl $%d, %%esp # esp -= args" ((i+1)*4);
"andl $~0xf, %esp # align esp down";
"movl %edx, (%esp) # arg[0] = rust_task "]
@ (list_init_concat i
begin
fun j ->
[ Printf.sprintf "movl %d(%%ebp),%%edx" ((j+7)*4);
Printf.sprintf "movl %%edx,%d(%%esp)" ((j+1)*4) ]
end)
@ ["movl 24(%ebp), %edx # edx = callee";
"call *%edx # call *%edx";
"movl 20(%ebp), %edx # edx = rust_task"]
@ load_esp_from_rust_sp
@ restore_callee_saves
@ ["ret"]))
end
in
let _ =
Llvm.set_module_inline_asm llmod
begin
String.concat "\n"
begin
List.map
begin
fun (sym,asm) ->
Printf.sprintf
"\t.globl %s%s\n\t.balign %d\n%s%s:\n\t%s"
prefix sym align prefix sym asm
end
glue
end
end
in
let decl_cdecl_fn name out_ty arg_tys =
let ty = Llvm.function_type out_ty arg_tys in
let fn = Llvm.declare_function name ty llmod in
Llvm.set_function_call_conv Llvm.CallConv.c fn;
fn
in
let decl_glue s =
let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in
let void_ty = Llvm.void_type llctx in
decl_cdecl_fn s void_ty [| task_ptr_ty |]
in
let decl_upcall n =
let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in
let word_ty = abi.Llabi.word_ty in
let callee_ty = word_ty in
let args_ty =
Array.append
[| task_ptr_ty; callee_ty |]
(Array.init n (fun _ -> word_ty))
in
let name = Printf.sprintf "rust_upcall_%d" n in
decl_cdecl_fn name word_ty args_ty
in
{
asm_activate_glue = decl_glue "rust_activate_glue";
asm_yield_glue = decl_glue "rust_yield_glue";
asm_upcall_glues = Array.init n_upcall_glues decl_upcall;
}
;;
(* x64-specific asm. *)
(* arm-specific asm. *)
(* ... *)
let get_glue
(llctx:Llvm.llcontext)
(llmod:Llvm.llmodule)
(abi:Llabi.abi)
(sess:Session.sess)
: asm_glue =
match sess.Session.sess_targ with
Linux_x86_elf
| Win32_x86_pe
| MacOS_x86_macho ->
x86_glue llctx llmod abi sess
;;
(*
* Local Variables:
* fill-column: 78;
* indent-tabs-mode: nil
* buffer-file-coding-system: utf-8-unix
* compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
* End:
*)
|