forked from ocaml/ocaml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbytesections.ml
164 lines (140 loc) · 4.98 KB
/
bytesections.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
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 2000 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Handling of sections in bytecode executable files *)
module Name = struct
type raw_name = string
type t =
| CODE (** bytecode *)
| CRCS (** crcs for modules *)
| DATA (** global data (constant) *)
| DBUG (** debug info *)
| DLLS (** dll names *)
| DLPT (** dll paths *)
| PRIM (** primitives names *)
| RNTM (** The path to the bytecode interpreter (use_runtime mode) *)
| SYMB (** global identifiers *)
| Other of raw_name
let of_string name =
match name with
| "CODE" -> CODE
| "DLPT" -> DLPT
| "DLLS" -> DLLS
| "DATA" -> DATA
| "PRIM" -> PRIM
| "SYMB" -> SYMB
| "DBUG" -> DBUG
| "CRCS" -> CRCS
| "RNTM" -> RNTM
| name ->
if String.length name <> 4 then
invalid_arg "Bytesections.Name.of_string: must be of size 4";
Other name
let to_string = function
| CODE -> "CODE"
| DLPT -> "DLPT"
| DLLS -> "DLLS"
| DATA -> "DATA"
| PRIM -> "PRIM"
| SYMB -> "SYMB"
| DBUG -> "DBUG"
| CRCS -> "CRCS"
| RNTM -> "RNTM"
| Other n -> n
end
type section_entry = {
name : Name.t;
pos : int;
len : int;
}
type section_table = {
sections : section_entry list;
first_pos : int
}
(* Recording sections *)
type toc_writer = {
(* List of all sections, in reverse order *)
mutable section_table_rev : section_entry list;
mutable section_prev : int;
outchan : out_channel;
}
let init_record outchan : toc_writer =
let pos = pos_out outchan in
{ section_prev = pos;
section_table_rev = [];
outchan }
let record t name =
let pos = pos_out t.outchan in
if pos < t.section_prev then
invalid_arg "Bytesections.record: out_channel offset moved backward";
let entry = {name; pos = t.section_prev; len = pos - t.section_prev} in
t.section_table_rev <- entry :: t.section_table_rev;
t.section_prev <- pos
let write_toc_and_trailer t =
let section_table = List.rev t.section_table_rev in
List.iter
(fun {name; pos = _; len} ->
let name = Name.to_string name in
assert (String.length name = 4);
output_string t.outchan name; output_binary_int t.outchan len)
section_table;
output_binary_int t.outchan (List.length section_table);
output_string t.outchan Config.exec_magic_number
(* Read the table of sections from a bytecode executable *)
exception Bad_magic_number
let read_toc ic =
let pos_trailer = in_channel_length ic - 16 in
seek_in ic pos_trailer;
let num_sections = input_binary_int ic in
let header =
really_input_string ic (String.length Config.exec_magic_number)
in
if header <> Config.exec_magic_number then raise Bad_magic_number;
let toc_pos = pos_trailer - 8 * num_sections in
seek_in ic toc_pos;
let section_table_rev = ref [] in
for _i = 1 to num_sections do
let name = Name.of_string (really_input_string ic 4) in
let len = input_binary_int ic in
section_table_rev := (name, len) :: !section_table_rev
done;
let first_pos, sections =
List.fold_left (fun (pos, l) (name, len) ->
let section = {name; pos = pos - len; len} in
(pos - len, section :: l)) (toc_pos, []) !section_table_rev
in
{ sections; first_pos }
let all t = t.sections
let pos_first_section t = t.first_pos
let find_section t name =
let rec find = function
| [] -> raise Not_found
| {name = n; pos; len} :: rest ->
if n = name
then pos, len
else find rest
in find t.sections
(* Position ic at the beginning of the section named "name",
and return the length of that section. Raise Not_found if no
such section exists. *)
let seek_section t ic name =
let pos, len = find_section t name in
seek_in ic pos; len
(* Return the contents of a section, as a string *)
let read_section_string t ic name =
really_input_string ic (seek_section t ic name)
(* Return the contents of a section, as marshalled data *)
let read_section_struct t ic name =
ignore (seek_section t ic name);
input_value ic