-
Notifications
You must be signed in to change notification settings - Fork 2
/
ld.ml
283 lines (272 loc) · 7.99 KB
/
ld.ml
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
open Emit
open Error
open Exe
open Opcode
open Syntax
exception Invalid
let global_tbl = Hashtbl.create 257
let global_tbl_used = ref 0
let const_tbl = Hashtbl.create 257
let prim_tbl = Hashtbl.create 257
let tag_tbl = Hashtbl.create 257
let make_slot_for_const c =
try
Hashtbl.find const_tbl c
with Not_found ->
let s = !global_tbl_used in
if s >= 65536 then (
prerr_endline "Used more than 65536 global table slots.";
exit 1
);
incr global_tbl_used;
Hashtbl.replace const_tbl c s;
if !Implementation.verbose then
Printf.printf "%s: slot %d of global table\n" (show_constant c) s;
s
let make_slot_for_global id =
try
Hashtbl.find global_tbl id
with Not_found ->
let s = !global_tbl_used in
if s >= 65536 then (
prerr_endline "Used more than 65536 global table slots.";
exit 1
);
incr global_tbl_used;
Hashtbl.replace global_tbl id s;
if !Implementation.verbose then
Printf.printf "%s: slot %d of global table\n" (string_of_long_ident id) s;
s
let make_slot_for_tag (id,stamp as tag) =
try
Hashtbl.find tag_tbl tag
with Not_found ->
let s = Hashtbl.length tag_tbl in
if s >= 256 then (
prerr_endline "Used more than 65536 tag table slots.";
exit 1
);
Hashtbl.replace tag_tbl tag s;
if !Implementation.verbose then
Printf.printf "%s,%d: slot %d of tag table\n" (string_of_long_ident id)
stamp s;
s
let get_slot_for_global id =
try
Hashtbl.find global_tbl id
with Not_found ->
Printf.eprintf "The global value \"%s\" is undefined.\n" (string_of_long_ident id);
exit 1
let get_num_of_prim name =
try
Hashtbl.find prim_tbl name
with Not_found ->
Printf.eprintf "The C primitive \"%s\" is not available.\n" name;
exit 1
let dump_data oc =
let pos = ref 0 in
let buf = ref (Bytes.create 16) in
let o u8 =
let len = Bytes.length !buf in
if !pos >= len then (
let newbuf = Bytes.create (2*len) in
Bytes.blit !buf 0 newbuf 0 !pos;
buf := newbuf
);
Bytes.set !buf !pos (Int32.(logand u8 255l |> to_int) |> char_of_int);
incr pos
in
let o' u8 =
let len = Bytes.length !buf in
if !pos >= len then (
let newbuf = Bytes.create (2*len) in
Bytes.blit !buf 0 newbuf 0 !pos;
buf := newbuf
);
Bytes.set !buf !pos (Int64.(logand u8 255L |> to_int) |> char_of_int);
incr pos
in
let oooo u32 =
o u32;
o Int32.(shift_right u32 8);
o Int32.(shift_right u32 16);
o Int32.(shift_right u32 24)
in
let oooo' u64 =
o' u64;
o' Int64.(shift_right u64 8);
o' Int64.(shift_right u64 16);
o' Int64.(shift_right u64 24);
o' Int64.(shift_right u64 32);
o' Int64.(shift_right u64 40);
o' Int64.(shift_right u64 48);
o' Int64.(shift_right u64 56)
in
let entries = ref [] and last = ref (-1) in
Hashtbl.iter (fun c slot -> entries := (slot,c) :: !entries) const_tbl;
entries := List.sort compare !entries;
if Config.word_size = 32 then (
List.iter (fun (slot,c) ->
for i = !last+1 to slot-1 do
o 1l;
oooo 1l
done;
last := slot;
match c with
| Const_char x ->
o 1l;
oooo Int32.(int_of_char x*2+1 |> of_int)
| Const_int x ->
o 1l;
oooo Int32.(add (mul (of_int x) 2l) 1l)
| Const_float x ->
let x = Int64.bits_of_float x in
o 0l;
oooo (make_header double_tag 2);
oooo (Int64.to_int32 x);
oooo Int64.(shift_right x 32 |> to_int32)
| Const_string x ->
let len = String.length x in
let w = 4 in
let size = len/w+1 in
o 0l;
oooo (make_string_header size);
String.iter (fun ch -> int_of_char ch |> Int32.of_int |> o) x;
let pad = w - len mod w in
for i = 1 to pad do
o (Int32.of_int pad)
done
) !entries;
for i = !last+1 to !global_tbl_used - 1 do
o 1l;
oooo 1l
done
) else (
List.iter (fun (slot,c) ->
for i = !last+1 to slot-1 do
o 1l;
oooo' 1L
done;
last := slot;
match c with
| Const_char x ->
o 1l;
oooo' Int64.(int_of_char x*2+1 |> of_int)
| Const_int x ->
o 1l;
oooo' Int64.(add (mul (of_int x) 2L) 1L)
| Const_float x ->
o 0l;
oooo' (make_header' double_tag 1);
oooo' (Int64.bits_of_float x)
| Const_string x ->
let len = String.length x in
let w = 8 in
let size = len/w+1 in
o 0l;
oooo' (make_string_header' size);
String.iter (fun ch -> int_of_char ch |> Int32.of_int |> o) x;
let pad = w - len mod w in
for i = 1 to pad do
o (Int32.of_int pad)
done
) !entries;
for i = !last+1 to !global_tbl_used - 1 do
o 1l;
oooo' 1L
done
);
output oc !buf 0 !pos
let link objs exefile =
let oc = open_out_bin exefile in
let scan first objfile =
if not (Filename.check_suffix objfile ".zo") then (
Printf.eprintf "Object files should be `*.zo'\n";
exit 1
);
let buf = Bytes.create 256 in
let ic = open_in_bin objfile in
if input ic buf 0 4 <> 4 then (
Printf.eprintf "Object file \"%s\" is invalid\n" objfile;
exit 2
);
if Bytes.sub_string buf 0 4 = Config.obj_magic32 then (
if Config.word_size <> 32 then (
Printf.eprintf "Cannot link 32-bit object file \"%s\".\n" objfile;
exit 2
)
) else if Bytes.sub_string buf 0 4 = Config.obj_magic64 then (
if Config.word_size <> 64 then (
Printf.eprintf "Cannot link 32-bit object file \"%s\".\n" objfile;
exit 2
)
) else (
Printf.eprintf "Object file \"%s\" has invalid magic.\n" objfile;
exit 2
);
let phr_idx_off = input_bin_int ic in
seek_in ic phr_idx_off;
let phr_idx = (input_value ic : compiled_phrase list) in
if first then
List.iter (fun cph ->
List.iter (fun (pos,reloc) ->
match reloc with
| Reloc_const c ->
make_slot_for_const c |> ignore
| Reloc_setglobal id ->
make_slot_for_global id |> ignore
| Reloc_tag(id,stamp) ->
make_slot_for_tag (id,stamp) |> ignore
| _ ->
()
) cph.cph_reloc
) phr_idx
else
List.iter (fun cph ->
let buf = Bytes.create cph.cph_len in
seek_in ic cph.cph_pos;
really_input ic buf 0 cph.cph_len;
List.iter (fun (pos,reloc) ->
match reloc with
| Reloc_const c ->
let s = make_slot_for_const c in
Bytes.set buf pos (char_of_int (s land 255));
Bytes.set buf (pos+1) (char_of_int (s lsr 8))
| Reloc_setglobal id
| Reloc_getglobal id ->
let s = make_slot_for_global id in
Bytes.set buf pos (char_of_int (s land 255));
Bytes.set buf (pos+1) (char_of_int (s lsr 8))
| Reloc_prim name ->
let s = get_num_of_prim name in
Bytes.set buf pos (char_of_int s)
| Reloc_tag(id,stamp) ->
let s = make_slot_for_tag (id,stamp) in
Bytes.set buf pos (char_of_int s)
) cph.cph_reloc;
output_bytes oc buf
) phr_idx
in
List.iter (scan true) objs;
output_bytes oc Config.exe_magic;
output_bin_int oc 0; (* global data offset *)
output_bin_int oc 0; (* global data num *)
List.iter (scan false) objs;
output_byte oc opSTOP;
let global_off = pos_out oc in
dump_data oc;
seek_out oc 4;
output_bin_int oc global_off;
output_bin_int oc !global_tbl_used
let init () =
Array.iteri (fun i name ->
Hashtbl.replace prim_tbl name i)
Cprim.name_of_prims;
List.iter (fun tag ->
match tag with
| Constr_tag_regular _ -> ()
| Constr_tag_extensible(id,stamp) ->
ignore @@ make_slot_for_tag (id,stamp))
[ Builtin.match_failure_tag
; Builtin.division_by_zero_tag
]