Skip to content

Commit 730cff3

Browse files
committed
adds semantics and supporting code for several x86 instructions
Adds the following instructions: - shufps - pmuldq - [v]packusdw - [v]packuswb - [v]packssdw - [v]packsswb - vzeroupper - movntd - xchgb The generated code for signed and unsigned saturation (the pack* family of instructions) is thoroughly optimized to minimize branching and comparison, which negatively affects analysis performance. Both signed and unsigned saturation are implemented as a lisp primitive that generates pure code with a single ite instruction and any comparisons are made with zero, i.e., no inequalities. To following extra changes support the added instructions: 1) [NEW] Extend x86 CPU family definition with 8-bit registers, e.g., AL,BL,CL,DL,AH,BH,CH,DH,SIL,DIL,BPL, and SPL. 2) [NEW] Added EFLAGS and RFLAGS aliases to the set of flag registers. 3) [NEW] It is now possible to use bool registers in the aliasing specifications. 4) [NEW] Added system and control register flags. 5) [FIX] Fixed a bug with incorrect reification of higher parts of aliased registers. 6) [NEW] Added a `dolist` macro to Primus Lisp. 7) [NEW] Added the `unquote` primitive to Primus Lisp. 8) [NEW] Added the `cast-saturate` primitive to Primus Lisp. 9) [NEW] Improved BIL code generation in case of empty if statements.
1 parent 13106cb commit 730cff3

22 files changed

+2060
-117
lines changed

.github/workflows/full.yml

+13-1
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,20 @@ jobs:
3232
dune-cache: true
3333
opam-disable-sandboxing: true
3434

35+
- name: Install BAP Dependencies
36+
run: opam install . --deps-only
37+
38+
- name: Configure BAP
39+
run: opam exec -- ocaml tools/configure.ml --with-llvm-config=$(opam var conf-bap-llvm:config)
40+
41+
- name: Build BAP
42+
run: opam exec -- dune build
43+
3544
- name: Install BAP
36-
run: opam install . --with-test
45+
run: opam exec -- dune install
46+
47+
- name: Run Unit Tests
48+
run: opam exec -- dune test --display=short
3749

3850
- name: Run Functional Tests
3951
run: opam exec -- make check

.github/workflows/main.yml

+5-9
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,13 @@ jobs:
99
matrix:
1010
os:
1111
- ubuntu-20.04
12-
- macos-11
1312
ocaml-compiler:
1413
- 4.08.x
1514
- 4.14.x
16-
exclude:
17-
- os: macos-11
18-
ocaml-compiler: 4.08.x
1915

2016

2117
runs-on: ${{ matrix.os }}
22-
continue-on-error: ${{ matrix.os == 'macos-11'}}
18+
continue-on-error: ${{ matrix.os == 'macos-latest'}}
2319

2420
env:
2521
TMPDIR: /tmp
@@ -39,16 +35,16 @@ jobs:
3935
sudo apt-get install dejagnu -y
4036
4137
- name: Prepare macOS
42-
if: matrix.os == 'macos-11'
38+
if: matrix.os == 'macos-latest'
4339
run: |
4440
echo 'LLVM_CONFIG=/usr/local/opt/llvm@9/bin/llvm-config' >> $GITHUB_ENV
45-
brew install deja-gnu
41+
brew install deja-gnu zstd
4642
4743
- name: Install OCaml
4844
uses: ocaml/setup-ocaml@v3
4945
with:
5046
ocaml-compiler: ${{ matrix.ocaml-compiler }}
51-
dune-cache: ${{ matrix.os != 'macos-11' }}
47+
dune-cache: ${{ matrix.os != 'macos-latest' }}
5248
opam-disable-sandboxing: true
5349
opam-local-packages: |
5450
*.opam
@@ -62,7 +58,7 @@ jobs:
6258
bap: git+https://github.com/BinaryAnalysisPlatform/opam-repository#testing
6359
6460
- name: Build BAP
65-
run: opam install bap.dev --with-test
61+
run: opam install bap.dev
6662

6763
- name: Run MC Functional Tests
6864
run: |

.github/workflows/nightly.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
uses: ocaml/setup-ocaml@v3
3636
with:
3737
ocaml-compiler: ${{ matrix.ocaml-compiler }}
38-
dune-cache: ${{ matrix.os != 'macos-11' }}
38+
dune-cache: ${{ matrix.os != 'macos-latest' }}
3939
opam-pin: false
4040
opam-disable-sandboxing: true
4141
opam-repositories: |

.github/workflows/oasis.yml

+9-9
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@ jobs:
99
matrix:
1010
os:
1111
- ubuntu-20.04
12-
- macos-11
1312
ocaml-compiler:
14-
- 4.08.x
1513
- 4.14.x
16-
exclude:
17-
- os: macos-11
18-
ocaml-compiler: 4.08.x
1914

2015

2116
runs-on: ${{ matrix.os }}
22-
continue-on-error: ${{ matrix.os == 'macos-11'}}
17+
continue-on-error: ${{ matrix.os == 'macos-latest'}}
2318

2419
env:
2520
TMPDIR: /tmp
@@ -39,7 +34,7 @@ jobs:
3934
sudo apt-get install dejagnu -y
4035
4136
- name: Prepare macOS
42-
if: matrix.os == 'macos-11'
37+
if: matrix.os == 'macos-latest'
4338
run: |
4439
echo 'LLVM_CONFIG=/usr/local/opt/llvm@9/bin/llvm-config' >> $GITHUB_ENV
4540
brew install deja-gnu
@@ -48,17 +43,22 @@ jobs:
4843
uses: ocaml/setup-ocaml@v3
4944
with:
5045
ocaml-compiler: ${{ matrix.ocaml-compiler }}
51-
dune-cache: ${{ matrix.os != 'macos-11' }}
46+
dune-cache: ${{ matrix.os != 'macos-latest' }}
5247
opam-disable-sandboxing: true
5348
opam-repositories: |
5449
default: git+https://github.com/ocaml/opam-repository.git
5550
bap: git+https://github.com/BinaryAnalysisPlatform/opam-repository#testing
51+
opam-local-packages: |
52+
*.opam
53+
!ppx_bap.opam
54+
!bap-ghidra.opam
55+
!bap-primus-symbolic-executor.opam
5656
5757
- name: Install OPAM dependencies
5858
run: opam install . --deps-only
5959

6060
- name: Install dependencies requires for the OASIS build
61-
run: opam install oasis ppx_bap conf-bap-llvm conf-binutils
61+
run: opam install oasis ppx_bap.master conf-bap-llvm conf-binutils
6262

6363
- name: Configure BAP
6464
run: >-

dune

+3-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
ppx_optcomp
4040
ppx_sexp_conv
4141
ppx_sexp_value
42-
ppx_variants_conv)
42+
ppx_variants_conv
43+
ppx_expect
44+
ppx_inline_test)
4345
(preprocess no_preprocessing))
4446

4547
(alias

dune-project

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
(lang dune 3.1)
2+
(cram enable)
23
(using dune_site 0.1)
34

45
(name bap)
@@ -1607,6 +1608,8 @@ and updating documents")
16071608
(ppx_here (and (>= v0.14) (< v0.16)))
16081609
(ppxlib (>= 0.15.0))
16091610
(ppx_optcomp (and (>= v0.14) (< v0.16)))
1611+
(ppx_expect (and (>= v0.14) (< v0.16)))
1612+
(ppx_inline_test (and (>= v0.14) (< v0.16)))
16101613
(ppx_sexp_conv (and (>= v0.14) (< v0.16)))
16111614
(ppx_sexp_value (and (>= v0.14) (< v0.16)))
16121615
(ppx_variants_conv (and (>= v0.14) (< v0.16)))))

lib/bap_core_theory/bap_core_theory.mli

+39-6
Original file line numberDiff line numberDiff line change
@@ -2140,6 +2140,10 @@ module Theory : sig
21402140
(** [reg x] defines [x] as a part. *)
21412141
val reg : 'a Bitv.t Var.t -> 'a part
21422142

2143+
(** [bit x] defines a boolean register [x] as a part.
2144+
@since 2.5.0 *)
2145+
val bit : Bool.t Var.t -> Bool.t part
2146+
21432147
(** [unk] defines an unnamed part of the register. *)
21442148
val unk : 'a part
21452149
end
@@ -2156,13 +2160,16 @@ module Theory : sig
21562160
origin register(s) and ['k] denotes the kind of relationship
21572161
between the alias and its origin.
21582162
2159-
Currently, we recognize two kinds of relationships. The [sub]
2163+
Currently, we recognize three kinds of relationships. The [sub]
21602164
kind defines the alias as a subset of the origin register, i.e.,
21612165
a contiguous sequnce of bits that are fully enclosed in the
21622166
origin register. The [sup] kind defines an alias as a superset
21632167
of a number of origin registers, i.e., it is a contiguous
21642168
sequence of bits formed as a concatenation of the origin
2165-
registers.
2169+
registers. Finally, the [set] register defines an alias as
2170+
superset of a numbero of origin register, where each origin
2171+
register is a boolean flag, i.e., an alias is a contiguous
2172+
sequence of one-bit flags.
21662173
21672174
More kinds of relationships could be added later.
21682175
@@ -2193,12 +2200,17 @@ module Theory : sig
21932200
(** the type index for the super-registers *)
21942201
type sup
21952202

2203+
(** the type index for a set of bits registers *)
2204+
type set
2205+
21962206
(** [cast_sub origin] recovers the kind of the origin. *)
21972207
val cast_sub : ('a,unit) t -> ('a,sub) t option
21982208

21992209
(** [cast_sup origin] recovers the kind of the origin. *)
22002210
val cast_sup : ('a,unit) t -> ('a,sup) t option
22012211

2212+
(** [cast_set origin] recovers the kind of the origin. *)
2213+
val cast_set : ('a,unit) t -> (Bool.t,set) t option
22022214

22032215
(** [reg origin] is the base register.
22042216
@@ -2218,7 +2230,7 @@ module Theory : sig
22182230
register. *)
22192231
val hi : ('a,sub) t -> int
22202232

2221-
(** [lo origin] returns the inclusive upper bound of the origin register
2233+
(** [lo origin] returns the inclusive lowe bound of the origin register
22222234
to which an alias belongs. *)
22232235
val lo : ('a,sub) t -> int
22242236

@@ -2229,10 +2241,21 @@ module Theory : sig
22292241
first element of the list corresponds to the most significant
22302242
part of the base register. This is the same order, in which
22312243
the aliasing was specified, e.g., if the aliasing was defined
2232-
as, [def x [reg hix; reg lox], then [regs] will
2244+
as, [def x [reg hix; reg lox]], then [regs] will
22332245
return [hix; lox].*)
22342246
val regs : ('a,sup) t -> 'a Bitv.t Var.t list
22352247

2248+
2249+
(** [bits origin] an list of flags that comprise the register.
2250+
The bits are sorted in the big endian order, i.e., the first
2251+
element of the list is the most significant part of the
2252+
alias. This is the same order, in which the aliasing was
2253+
specified, e.g., if the aliasing was defined as,
2254+
[def status [bit cf; bit zf]], then [regs] will return [cf; zf].
2255+
2256+
@since 2.5.0 *)
2257+
val bits : (Bool.t,set) t -> Bool.t Var.t list
2258+
22362259
end
22372260

22382261
(** A target-specific role of program entities.
@@ -2305,7 +2328,7 @@ module Theory : sig
23052328
(** the register is used by the integer arithmetic unit
23062329
23072330
This role can be assigned both to general and special
2308-
purpose registers. E.g., to get integer arithemtic status
2331+
purpose registers. E.g., to get integer arithmetic status
23092332
control registers use [[special; integer]]. *)
23102333
val integer : t
23112334

@@ -2347,10 +2370,20 @@ module Theory : sig
23472370
(** the constant register that always holds zero. *)
23482371
val zero : t
23492372

2373+
(** the constant register that always holds one.
2374+
@since 2.5.0 *)
2375+
val one : t
23502376

2351-
(** the program status register *)
2377+
(** the program status register. *)
23522378
val status : t
23532379

2380+
(** a register for controlling operating system. *)
2381+
val system : t
2382+
2383+
(** a register that controls CPU or other device.
2384+
@since 2.5.0 *)
2385+
val control : t
2386+
23542387
(** the zero flag register
23552388
23562389
Is set when an arithmetic operation results in zero.*)

lib/bap_core_theory/bap_core_theory_pass.ml

+43-19
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ module Desugar(CT : Core) : Core = struct
8888

8989
let pass = Effect.empty Effect.Sort.bot
9090

91-
9291
let take what bits x =
9392
what (Val.Bitv.define bits) (CT.var x)
9493

@@ -112,24 +111,24 @@ module Desugar(CT : Core) : Core = struct
112111
let module Pos = Bitvec.M32 in
113112
CT.int (Val.Bitv.define 32) (Pos.int x)
114113

115-
let assign_regs lhs rhs =
114+
let assign_multi size cast lhs rhs =
116115
rhs >>= fun rhs ->
117116
let total = Val.(Bitv.size (sort rhs)) in
118-
fst@@List.fold lhs ~init:(!!pass,total+1) ~f:(fun (data,hi) lhs ->
117+
fst@@List.fold lhs ~init:(!!pass,total+1) ~f: (fun (data,hi) lhs ->
119118
let s = Var.sort lhs in
120-
let bits = Val.Bitv.size s in
119+
let bits = size s in
121120
let lo = hi - bits in
122-
let rhs = CT.extract s (pos hi) (pos lo) !!rhs in
121+
let s' = Val.Bitv.define bits in
122+
let rhs = cast (CT.extract s' (pos hi) (pos lo) !!rhs) in
123123
CT.(seq data (set lhs rhs),hi - bits))
124124

125+
let assign_regs lhs rhs = assign_multi Val.Bitv.size Fn.id lhs rhs
126+
let assign_bits lhs rhs =
127+
assign_multi (Fn.const 1) CT.(fun v ->ite (is_zero v) b0 b1) lhs rhs
125128

126129
(* module Alias ensures that only bitvec registers
127130
are involved in aliasing *)
128-
let cast_var v =
129-
match Val.Bitv.refine @@ Val.Sort.forget @@ Var.sort v with
130-
| None -> assert false
131-
| Some s -> Var.resort v s
132-
and cast_val v = v >>| fun v ->
131+
let cast_val v = v >>| fun v ->
133132
match Val.resort Val.Bitv.refine (Val.forget v) with
134133
| None -> assert false
135134
| Some v -> v
@@ -150,22 +149,35 @@ module Desugar(CT : Core) : Core = struct
150149
CT.set (Origin.reg s) x
151150
| Some s -> assign_sub (Origin.reg s) x (Origin.lo s)
152151
| None -> match Origin.cast_sup origin with
153-
| None -> !!pass
154152
| Some s -> assign_regs (Origin.regs s) x
153+
| None -> match Origin.cast_set origin with
154+
| Some s -> assign_bits (Origin.bits s) x
155+
| None -> !!pass
156+
155157

156-
let var r =
158+
let const role value ret t r s =
159+
if Target.has_roles t [role] r
160+
then match Val.Bitv.refine (Val.Sort.forget s) with
161+
| None -> Some (CT.unk s)
162+
| Some s' -> Some (ret@@CT.int s' value)
163+
else None
164+
165+
let consts = [
166+
Target.Role.Register.zero, Bitvec.zero;
167+
Target.Role.Register.one, Bitvec.one;
168+
]
169+
170+
let var (type a) r =
157171
Scope.mem r >>= function
158172
| true -> CT.var r
159173
| false ->
160174
let* t = target in
161175
let s = Var.sort r in
162176
let ret x = x >>| fun x -> KB.Value.refine x s in
163-
if Target.has_roles t [Target.Role.Register.zero] r
164-
then match Val.Bitv.refine (Val.Sort.forget s) with
165-
| None -> CT.unk s
166-
| Some s' ->
167-
ret@@CT.int s' Bitvec.zero
168-
else
177+
List.find_map consts ~f:(fun (role,value) ->
178+
const role value ret t r s) |> function
179+
| Some v -> v
180+
| None ->
169181
match Target.unalias t r with
170182
| None -> CT.var r
171183
| Some origin ->
@@ -178,13 +190,25 @@ module Desugar(CT : Core) : Core = struct
178190
ret @@
179191
CT.extract bs (pos hi) (pos lo) (CT.var (Origin.reg sub))
180192
| None -> match Origin.cast_sup origin with
181-
| None -> CT.unk s
182193
| Some sup ->
183194
let regs = Origin.regs sup in
184195
let total = List.sum (module Int) regs ~f:(fun r ->
185196
Val.Bitv.size (Var.sort r)) in
186197
let bs = Val.Bitv.define total in
187198
ret @@ CT.concat bs (List.map regs ~f:CT.var)
199+
| None ->
200+
match Origin.cast_set origin with
201+
| Some set ->
202+
let bits = Origin.bits set in
203+
let n = List.length bits in
204+
let bs = Val.Bitv.define n in
205+
let us = Val.Bitv.define 1 in
206+
let m0 = CT.int us Bitvec.zero
207+
and m1 = CT.int us Bitvec.one in
208+
ret @@ CT.concat bs (List.map bits ~f:(fun v ->
209+
CT.(ite (var v) m1 m0)))
210+
| none -> CT.unk s
211+
188212

189213
let let_ v x y =
190214
x >>= fun x ->

0 commit comments

Comments
 (0)