summaryrefslogtreecommitdiff
path: root/cparser/PackedStructs.ml
diff options
context:
space:
mode:
Diffstat (limited to 'cparser/PackedStructs.ml')
-rw-r--r--cparser/PackedStructs.ml105
1 files changed, 50 insertions, 55 deletions
diff --git a/cparser/PackedStructs.ml b/cparser/PackedStructs.ml
index 4b5d0e1..5e0a032 100644
--- a/cparser/PackedStructs.ml
+++ b/cparser/PackedStructs.ml
@@ -16,6 +16,7 @@
(* Emulation of #pragma pack (experimental) *)
open Printf
+open Machine
open C
open Cutil
open Env
@@ -24,7 +25,7 @@ open Transform
type field_info = {
fi_offset: int; (* byte offset within struct *)
- fi_swap: ikind option (* Some ik if byte-swapped *)
+ fi_swap: bool (* true if byte-swapped *)
}
(* Mapping from (struct name, field name) to field_info.
@@ -59,22 +60,12 @@ let layout_struct mfa msa swapped loc env struct_id fields =
if f.fld_bitfield <> None then
error "%a: Error: bitfields in packed structs not allowed"
formatloc loc;
- let swap =
- if swapped then begin
- match unroll env f.fld_typ with
- | TInt(ik, _) ->
- if sizeof_ikind ik = 1 then None else Some ik
- | _ ->
- error "%a: Error: byte-swapped fields must have integer type"
- formatloc loc;
- None
- end else
- None in
let (sz, al) =
match sizeof env f.fld_typ, alignof env f.fld_typ with
| Some s, Some a -> (s, a)
| _, _ -> error "%a: struct field has incomplete type" formatloc loc;
(0, 1) in
+ let swap = swapped && sz > 1 in
let al1 = min al mfa in
let pos1 = align pos al1 in
Hashtbl.add packed_fields
@@ -123,9 +114,22 @@ let lookup_function loc env name =
with Env.Error msg ->
fatal_error "%a: Error: %s" formatloc loc (Env.error_message msg)
+(* Type for the access *)
+
+let accessor_type loc env ty =
+ match unroll env ty with
+ | TInt(ik,_) -> (8 * sizeof_ikind ik, TInt(unsigned_ikind_of ik,[]))
+ | TPtr _ -> (8 * !config.sizeof_ptr, TInt(ptr_t_ikind,[]))
+ | _ ->
+ error "%a: unsupported type for byte-swapped field access" formatloc loc;
+ (32, TVoid [])
+
(* (ty) e *)
let ecast ty e = {edesc = ECast(ty, e); etyp = ty}
+let ecast_opt env ty e =
+ if compatible_types env ty e.etyp then e else ecast ty e
+
(* *e *)
let ederef ty e = {edesc = EUnop(Oderef, e); etyp = ty}
@@ -148,32 +152,26 @@ let arrow_packed_field base pf ty =
etyp = TArray(TInt(IChar,[]),None,[]) } in
ederef ty (ecast (TPtr(ty, [])) (eoffset payload pf.fi_offset))
-(* (ty) __builtin_read_intNN_reversed(&lval) *)
-let bswap_read loc env lval ik =
- let uik = unsigned_ikind_of ik in
- let bsize = sizeof_ikind ik * 8 in
+(* (ty) __builtin_read_NN_reversed(&lval) *)
+let bswap_read loc env lval ty =
+ let (bsize, aty) =
+ accessor_type loc env ty in
let (id, fty) =
- lookup_function loc env (sprintf "__builtin_read_int%d_reversed" bsize) in
+ lookup_function loc env (sprintf "__builtin_read%d_reversed" bsize) in
let fn = {edesc = EVar id; etyp = fty} in
- let args =
- if uik = ik
- then [eaddrof lval]
- else [ecast (TPtr(TInt(uik,[]),[])) (eaddrof lval)] in
- let call = {edesc = ECall(fn, args); etyp = TInt(uik, [])} in
- if ik = uik then call else ecast (TInt(ik,[])) call
+ let args = [ecast (TPtr(aty,[])) (eaddrof lval)] in
+ let call = {edesc = ECall(fn, args); etyp = aty} in
+ ecast_opt env ty call
(* __builtin_write_intNN_reversed(&lhs,rhs) *)
-let bswap_write loc env lhs rhs ik =
- let uik = unsigned_ikind_of ik in
- let bsize = sizeof_ikind ik * 8 in
+let bswap_write loc env lhs rhs ty =
+ let (bsize, aty) =
+ accessor_type loc env ty in
let (id, fty) =
- lookup_function loc env (sprintf "__builtin_write_int%d_reversed" bsize) in
+ lookup_function loc env (sprintf "__builtin_write%d_reversed" bsize) in
let fn = {edesc = EVar id; etyp = fty} in
- let args =
- if uik = ik
- then [eaddrof lhs; rhs]
- else [ecast (TPtr(TInt(uik,[]),[])) (eaddrof lhs);
- ecast (TInt(uik,[])) rhs] in
+ let args = [ecast_opt env (TPtr(aty,[])) (eaddrof lhs);
+ ecast_opt env aty rhs] in
{edesc = ECall(fn, args); etyp = TVoid[]}
(* Expressions *)
@@ -193,15 +191,14 @@ let transf_expr loc env ctx e =
| _ -> None in
(* Transformation of l-values. Return transformed expr plus
- [Some ik] if l-value is a byte-swapped field of kind [ik]
- or [None] otherwise. *)
+ [true] if l-value is a byte-swapped field and [false] otherwise. *)
let rec lvalue e =
match e.edesc with
| EUnop(Odot fieldname, e1) ->
let e1' = texp Val e1 in
begin match is_packed_access e1.etyp fieldname with
| None ->
- ({edesc = EUnop(Odot fieldname, e1'); etyp = e.etyp}, None)
+ ({edesc = EUnop(Odot fieldname, e1'); etyp = e.etyp}, false)
| Some pf ->
(dot_packed_field e1' pf e.etyp, pf.fi_swap)
end
@@ -209,12 +206,15 @@ let transf_expr loc env ctx e =
let e1' = texp Val e1 in
begin match is_packed_access_ptr e1.etyp fieldname with
| None ->
- ({edesc = EUnop(Oarrow fieldname, e1'); etyp = e.etyp}, None)
+ ({edesc = EUnop(Oarrow fieldname, e1'); etyp = e.etyp}, false)
| Some pf ->
(arrow_packed_field e1' pf e.etyp, pf.fi_swap)
end
+ | EBinop(Oindex, e1, e2, tyres) ->
+ let (e1', swap) = lvalue e1 in
+ ({edesc = EBinop(Oindex, e1', e2, tyres); etyp = e.etyp}, swap)
| _ ->
- (texp Val e, None)
+ (texp Val e, false)
and texp ctx e =
match e.edesc with
@@ -222,17 +222,14 @@ let transf_expr loc env ctx e =
| ESizeof _ -> e
| EVar _ -> e
- | EUnop(Odot _, _) | EUnop(Oarrow _, _) ->
+ | EUnop(Odot _, _) | EUnop(Oarrow _, _) | EBinop(Oindex, _, _, _) ->
let (e', swap) = lvalue e in
- begin match swap with
- | None -> e'
- | Some ik -> bswap_read loc env e' ik
- end
+ if swap then bswap_read loc env e' e'.etyp else e'
| EUnop((Oaddrof|Opreincr|Opredecr|Opostincr|Opostdecr as op), e1) ->
let (e1', swap) = lvalue e1 in
- if swap <> None then
- error "%a: Error: &, ++ and -- over byte-swap field are not supported"
+ if swap then
+ error "%a: Error: &, ++ and -- over byte-swapped field are not supported"
formatloc loc;
{edesc = EUnop(op, e1'); etyp = e.etyp}
@@ -242,23 +239,21 @@ let transf_expr loc env ctx e =
| EBinop(Oassign, e1, e2, ty) ->
let (e1', swap) = lvalue e1 in
let e2' = texp Val e2 in
- begin match swap with
- | None ->
- {edesc = EBinop(Oassign, e1', e2', ty); etyp = e.etyp}
- | Some ik ->
- if ctx <> Effects then
- error "%a: Error: assignment over byte-swapped field in value context is not supported"
- formatloc loc;
- bswap_write loc env e1' e2' ik
- end
+ if swap then begin
+ if ctx <> Effects then
+ error "%a: Error: assignment over byte-swapped field in value context is not supported"
+ formatloc loc;
+ bswap_write loc env e1' e2' e1'.etyp
+ end else
+ {edesc = EBinop(Oassign, e1', e2', ty); etyp = e.etyp}
| EBinop((Oadd_assign|Osub_assign|Omul_assign|Odiv_assign|Omod_assign|
Oand_assign|Oor_assign|Oxor_assign|Oshl_assign|Oshr_assign as op),
e1, e2, ty) ->
let (e1', swap) = lvalue e1 in
let e2' = texp Val e2 in
- if swap <> None then
- error "%a: Error: op-assignment over byte-swapped field in value context is not supported"
+ if swap then
+ error "%a: Error: op-assignment over byte-swapped field is not supported"
formatloc loc;
{edesc = EBinop(op, e1', e2', ty); etyp = e.etyp}