summaryrefslogtreecommitdiff
path: root/powerpc/eabi/CPragmas.ml
blob: d4b79b5257e95e8d8fc6e7ad6cb76cdff19c38f6 (plain)
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
(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)

(* Platform-dependent handling of pragmas *)

open Printf
open Cil
open Camlcoq

type section_info = {
  sec_name_init: string;
  sec_name_uninit: string;
  sec_acc_mode: string;
  sec_near_access: bool
}

let default_section_info = {
  sec_name_init = ".data";
  sec_name_uninit = ".data"; (* COMM? *)
  sec_acc_mode = "RW";
  sec_near_access = false
}

let section_table : (string, section_info) Hashtbl.t =
  Hashtbl.create 17

(* Built-in sections *)

let _ =
  let rodata =
    if Configuration.system = "linux" then ".rodata" else ".text" in
  List.iter (fun (n, si) -> Hashtbl.add section_table n si) [
     "CODE",  {sec_name_init = ".text";
               sec_name_uninit = ".text";
               sec_acc_mode = "RX";
               sec_near_access = false};
     "DATA",  {sec_name_init = ".data";
               sec_name_uninit = ".data"; (* COMM? *)
               sec_acc_mode = "RW";
               sec_near_access = false};
     "SDATA", {sec_name_init = ".sdata";
               sec_name_uninit = ".sbss";
               sec_acc_mode = "RW";
               sec_near_access = true};
     "CONST", {sec_name_init = rodata;
               sec_name_uninit = rodata;
               sec_acc_mode = "R";
               sec_near_access = false};
     "SCONST",{sec_name_init = ".sdata2";
               sec_name_uninit = ".sdata2";
               sec_acc_mode = "R";
               sec_near_access = true};
     "STRING",{sec_name_init = rodata;
               sec_name_uninit = rodata;
               sec_acc_mode = "R";
               sec_near_access = false}
  ]

let process_section_pragma classname istring ustring addrmode accmode =
  let old_si =
    try Hashtbl.find section_table classname
    with Not_found -> default_section_info in
  let si =
    { sec_name_init =
        if istring = "" then old_si.sec_name_init else istring;
      sec_name_uninit =
        if ustring = "" then old_si.sec_name_uninit else ustring;
      sec_acc_mode =
        if accmode = "" then old_si.sec_acc_mode else accmode;
      sec_near_access =
        if addrmode = ""
        then old_si.sec_near_access
        else (addrmode = "near-code") || (addrmode = "near-data") } in
  Hashtbl.add section_table classname si


let use_section_table : (AST.ident, section_info) Hashtbl.t =
  Hashtbl.create 51

let process_use_section_pragma classname id =
  try
    let info = Hashtbl.find section_table classname in
    Hashtbl.add use_section_table (intern_string id) info
  with Not_found ->
    Cil2Csyntax.error (sprintf "unknown section name `%s'" classname)

let default_use_section id classname =
  if not (Hashtbl.mem use_section_table id) then begin
    let info =
      try Hashtbl.find section_table classname
      with Not_found -> assert false in
    Hashtbl.add use_section_table id info
  end

let define_function id v =
  default_use_section id "CODE"

let define_stringlit id v =
  default_use_section id "STRING"

let define_variable id v =
  let sz = Cil.bitsSizeOf v.vtype / 8 in
  let sect =
    if Cil2Csyntax.var_is_readonly v then
      if sz <= !Clflags.option_small_const then "SCONST" else "CONST"
    else
      if sz <= !Clflags.option_small_data then "SDATA" else "DATA" in
  default_use_section id sect

(* CIL does not parse the "section" and "use_section" pragmas, which
   have irregular syntax, so we parse them using regexps *)

let re_start_pragma_section = Str.regexp "section\\b"

let re_pragma_section = Str.regexp(
  "section[ \t]+"
^ "\\([A-Za-z_][A-Za-z_0-9]*\\)[ \t]+"  (* class_name *)
^ "\\(\"[^\"]*\"\\)?[ \t]*"             (* istring *)
^ "\\(\"[^\"]*\"\\)?[ \t]*"             (* ustring *)
^ "\\(standard\\|near-absolute\\|far-absolute\\|near-data\\|far-data\\|near-code\\|far-code\\)?[ \t]*"                  (* addressing mode *)
^ "\\([RWXON]*\\)"                      (* access mode *)
)

let re_start_pragma_use_section = Str.regexp "use_section\\b"

let re_pragma_use_section = Str.regexp
  "use_section[ \t]+\
   \\([A-Za-z_][A-Za-z_0-9]*\\)[ \t]+\
   \\(.*\\)$"

let re_split_idents = Str.regexp "[ \t,]+"

let process_pragma (Attr(name, _)) =
  if Str.string_match re_pragma_section name 0 then begin
    process_section_pragma
      (Str.matched_group 1 name) (* classname *)
      (Str.matched_group 2 name) (* istring *)
      (Str.matched_group 3 name) (* ustring *)
      (Str.matched_group 4 name) (* addrmode *)
      (Str.matched_group 5 name); (* accmode *)
    true
  end else if Str.string_match re_start_pragma_section name 0 then
    Cil2Csyntax.error "ill-formed `section' pragma"
 else if Str.string_match re_pragma_use_section name 0 then begin
    let classname = Str.matched_group 1 name
    and idents = Str.matched_group 2 name in
    let identlist = Str.split re_split_idents idents in
    if identlist = [] then Cil2Csyntax.warning "vacuous `use_section' pragma";
    List.iter (process_use_section_pragma classname) identlist;
    true
  end else if Str.string_match re_start_pragma_use_section name 0 then
    Cil2Csyntax.error "ill-formed `use_section' pragma"
  else
    false

let initialize () =
  Cil2Csyntax.process_pragma_hook := process_pragma;
  Cil2Csyntax.define_variable_hook := define_variable;
  Cil2Csyntax.define_function_hook := define_function;
  Cil2Csyntax.define_stringlit_hook := define_stringlit

(* PowerPC-specific: say if an atom is in a small data area *)

let atom_is_small_data a ofs =
  begin try
    let v = Hashtbl.find Cil2Csyntax.varinfo_atom a in
    let sz = Cil.bitsSizeOf v.vtype / 8 in
    let ofs = camlint_of_coqint ofs in
    if ofs >= 0l && ofs < Int32.of_int sz then begin
      try
        (Hashtbl.find use_section_table a).sec_near_access
      with Not_found ->
        if Cil2Csyntax.var_is_readonly v
        then sz <= !Clflags.option_small_const
        else sz <= !Clflags.option_small_data
    end else
      false
  with Not_found ->
    false
  end

(* PowerPC-specific: determine section to use for a particular symbol *)

let section_for_atom a init =
  try
    let sinfo = Hashtbl.find use_section_table a in
    let sname =
      if init then sinfo.sec_name_init else sinfo.sec_name_uninit in
    if not (String.contains sname '\"') then
      Some sname
    else begin
      (* The following is Diab-specific... *)
      let accmode = sinfo.sec_acc_mode in
      let is_writable = String.contains accmode 'W'
      and is_executable = String.contains accmode 'X' in
      let stype =
        match is_writable, is_executable with
        | true, true -> 'm'                 (* text+data *)
        | true, false -> 'd'                (* data *)
        | false, true -> 'c'                (* text *)
        | false, false -> 'r'               (* const *)
      in Some(sprintf ".section\t%s,,%c" sname stype)
    end
  with Not_found -> None