Ranjit Jhala Rupak Majumdar
Bit-level Types for
High-level Reasoning
The Problem
• Bit-level operators in low-level systems code• Why ?
– Interact with hardware – Reduce memory footprint
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte = (p & 0xFFFFF000)>> 12;
b = tab[pte] & 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte = (p & 0xFFFFF000)>> 12;
b = tab[pte] & 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
The Problem
• Bit-level operators in low-level systems code
• Inscrutable to humans, optimizers, verifiers
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte = (p & 0xFFFFF000)>> 12;
b = tab[pte] & 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte = (p & 0xFFFFF000)>> 12;
b = tab[pte] & 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
Whats going on ?
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
32
p
31 1
Whats going on ?
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
31 1
p
pte
12 20
20 11 120
Whats going on ?
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
p
pte
20 11 1
12 20
32
tab[pte]
Whats going on ?
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
p
pte
20 11 1
12 20
b
30 2
20 10 11
o
1012 2
Whats going on ?
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
p
pte
12 20
b
30 2
20 10 11
o
1020 2
Q: How to infer complex information flow to understand, optimize, verify code ?
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
p
pte
12 20
b
30 2
20 10 11
o
1020 2
Plan
• Motivation
• Approach
Our approach: (1) Bit-level Types
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,12}{idx,20}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
Bit-level TypesSequences of {name,size} pairs
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
Expressions ! RecordsBit-ops ! Field accesses
if (p.rd == 0){
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
if (p.rd == 0){
Expressions ! RecordsBit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
if (p.rd == 0){
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
pte.idx = p.idx;
Expressions ! RecordsBit-ops ! Field accesses
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
if (p.rd == 0){
pte.idx = p.idx;
Expressions ! RecordsBit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
if (p.rd == 0){
pte.idx = p.idx;
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2} b.addr = tab[pte.idx].addr;
Expressions ! RecordsBit-ops ! Field accesses
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
b.addr = tab[pte.idx].addr;
if (p.rd == 0){
pte.idx = p.idx;
Expressions ! RecordsBit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
b.addr = tab[pte.idx].addr;
if (p.rd == 0){
pte.idx = p.idx;
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2} o.addr = p.addr;
Expressions ! RecordsBit-ops ! Field accesses
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
o.addr = p.addr;
b.addr = tab[pte.idx].addr;
if (p.rd == 0){
pte.idx = p.idx;
Expressions ! RecordsBit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
o.addr = p.addr;
b.addr = tab[pte.idx].addr;
if (p.rd == 0){
pte.idx = p.idx;
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2} return m[b.addr + o.addr];
Expressions ! RecordsBit-ops ! Field accesses
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
o.addr = p.addr;
return m[b.addr + o.addr];
b.addr = tab[pte.idx].addr;
if (p.rd == 0){
pte.idx = p.idx;
Expressions ! RecordsBit-ops ! Field accesses
Our approach
mget(p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget(p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
Low-level operations eliminated bit-level types + translation
o.addr = p.addr;
return m[b.addr + o.addr];
b.addr = tab[pte.idx].addr;
if (p.rd == 0){
pte.idx = p.idx;
Program can be understood, optimized, verified
Plan• Motivation
• Approach – Bit-level types + Translation
• Key: Bit-level type Inference
• Experiences
• Related work
Constraint-based Type InferenceAlgorithm:0. Variables for unknowns1. Generate constraints on vars2. Solve constraints
2a = b – 10b = 2006 - 1952
Alice’s age: a Bob’s age: b
= 22= 54
Remember these: If Alice doubles her age, she would still be
10 years younger than Bob, who was born in 1952. How old are Alice and Bob ?
Constraint-based Type InferenceAlgorithm:
0. Variables for unknown• bit-level types of all program expressions
1. Generate constraints on vars
2. Solve constraints
Plan• Motivation
• Approach – Bit-level types + Translation
• Key: Bit-level type Inference– Constraint Generation– Constraint Solving
• Experiences
• Related work
Constraint Generation
Type variables for each
expression: p p p&0x1 p&0x1 pte pte
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
Generating Zero Constraints
Mask:
p&0xFFC[31:12] = ;
p&0xFFC[1:0] = ;
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
020 02
1231 1 0
Generating Zero Constraints
012mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
Shift:
e>>12[31:20]= ;
e is p&0xFFFFF000
2031
Why are zeros special ?Consider assignment (value flows e to x)
Should x and e have same bit-level type?
x = e
K
K +
Common idiom: k-bit values special case of k+-bit values• Equality results in unnecessary breaks• Zeros enable precise subtyping
subtypes(·)
·
x
e
Inequality constraint
x ¸ e
Generating Inequality Constraints
Mask:
p&0xFFC[11:2] ¸ p[11:2]
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
020 02
11 2
Shift:
e>>12[19:0] ¸ e[31:12]
012
Generating Inequality Constraints
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
19
31 12
0
e
e>>12
Generating Inequality Constraints
Assignment:
o ¸p&0xFFC
that is…
o[31:0] ¸ p&0xFFC[31:0]
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
Plan• Motivation
• Approach – Bit-level types + Translation
• Key: Bit-level type Inference– Constraint Generation– Constraint Solving
• Experiences
• Related work
Constraint SolutionsSolution is an assignment • A: type variables ! bit-level typesA()[i:j] = subsequence of A() from bit i
through j
20 10 11
p)= {idx,20}{addr,10}{wr,1}{rd,1}
• A(p)[12:1] = {addr,10} {wr,1}
• A(p)[31:2] = {idx,20} {addr,10}
• A(p)[31:5] = undefined
12 131 25
Constraint Solving OverviewSolution is an assignment • A: type variables ! bit-level types
A([i:j]) = subsequence from bit i through j
A satisfies:• zero Constraint : [i:j] = ;
– If A()[i:j] = ;i-j+1
• inequality Constraint: [i:j] · ’[i’:j’]– If A()[i:j] · A(’)[i’:j’]
• In both cases, A()[i:j] must be defined
Constraint Solving AlgorithmInput: Zero constraints {z_1,…,z_m}
Inequality constraints {c1,…,cn}
Output: Assignment satisfying all constraints
A = A0
for i in [1…n]:A = refine(A,ci)
return A
A0 = Initial asgn satisfying zero constraints (details in paper)
refine(A,ci) adjusts A such that:
• ci becomes satisfied
• earlier constraints stay satisfied • built using Split, Unify
Refine: Split(A,,k)
f,12
A() p,3212
A’()
A’ = Split(A,,12)
Throughout A, substitute:
p,12 + 12
f,12e,
where e , f are fresh
e,20
p,12-
f,12-
and substitute:
Refine: Split(A,,k)• Used to ensure A()[i:j] is defined
2
f,12
g,10
A() p,3211+1
A’()
A’’() e,20 h,2
e,20
A’ = Split(A,,12)
Ensure A([11:2] is defined
A’’ = Split(A’,,2)
11
11 2
A’’([11:2] defined
Refine: Unify(A,p,q)
p,
q,
Throughout A, substitute:
Refine(A, [31:12] · ’[19:0])
r :12
A(’) p : 32
A() ; :10 q :10
A(’)[19:0] undefined
A’ = Split(A,’,19+1)
A’’ = Unify(A’,q,t)
1231
019
r : 12
A’(’) t : 20
A’() ; :10 q :10
s : 12
1231
019
r : 12
A’’(’) t : 32
A’’() ; :10 t :10
A’’ satisfies constraint
t : 32
1231
019
A’(’)[19:0]
A’()[31:12] ·
Constraint SolvingInput: ConstraintsOutput: Assignment satisfying all constraints
A = A0
for i in [1…n]:A = refine(A,ci)
return A
Substitution (in Split, Unify)• ensures earlier constraints stay satisfied• most general solution found• Efficiently implemented using graphs
Plan• Motivation
• Approach – Bit-level types + Translation
• Key: Bit-level type Inference– Constraint Generation– Constraint Solving
• Experiences
• Related work
Experiences
Implemented bit-level type inference for C
• pmap: a kernel virtual memory system• Implements the code for our running example
• mondrian: a memory protection system
• scull: a linux device driver (1-3 Kloc)
• Inference/Translation takes less than 1s
Mondrian [Witchel et. al.]
• Bit packing for memory and permission bits– 2600 lines of code, generated 775 constraints– Translated to program without bit-operations– 18 different bit-packed structures
• 10 assertions provided by programmer– After translation, assertions verified using BLAST– 6 safe: all require bit-level reasoning
• Previously, verification was not possible
– 4 false positives: imprecise modeling of arrays
Cop outs (i.e. Future Work)1. Truly binary bit-vector operations
– x << y, x && y– Currently: Value-flow analysis to infer constants flowing
to y Break into a switch statement
2. Flow-sensitivity• Currently: SSA renaming
3. Arithmetic overflow• does a k-bit value “spill over”• Currently: Assume no overflow
4. Path-sensitivity (value dependent types)• Type of suffix depends on value of first field• e.g. Instruction decoder for architecture simulator
• Number/type of operands depends on opcode
Plan• Motivation
• Approach – Bit-level types + Translation
• Key: Bit-level type Inference– Constraint Generation– Constraint Solving
• Experiences
• Related work
Related Work• O Callahan – Jackson [ICSE 97]
– Type Inference
• Gupta et. al. [POPL 03, CC02] – Dataflow analyses for packing bit-sections
• Ramalingam et. al. [POPL 99] – Aggregate structure inference for COBOL
Conclusions• (Automatic) reasoning about Bit-operations hard
• Structure: bit-operations pack data into one word
• Structure Inferred via Bit-level Type Inference
• Structure Exploited via Translation to fields
• Precise, efficient reasoning about Bit-operations
Thank youThank you
Previous approaches model bitwise ops by:
1. Uninterpreted functions • Imprecise
2. Logical axioms • Inefficient
3. Bit-blasting terms into 32/64-bits• Lose high-level relationships
Q: How to infer complex information flow to understand, optimize, verify code ?
Refine• Two basic operations: split, unify• Split(A,,[i:j]): ensures A()[i:j] is defined
2
f : 12
g : 10
A() p : 32
11+1
A’()
A’’() e : 20 h:2
Split(A,,[11:2])A’ = in A, substitute:
p : +(11+1)
11+1
f : 11+1e :
where e , f are freshe : 20
A’’ = in A’, substitute:
f : +2 h : 2g :
where g,h are fresh
2
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
• Expressions ! Records• Bit-ops ! Field accesses
if (p.rd == 0){
pte.idx = p.idx;
b.addr = tab[pte.idx].addr;
o.addr = p.addr;
return m[o.addr + p.addr];
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
• Expressions ! Records• Bit-ops ! Field accesses
if (p.rd == 0){
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
• Expressions ! Records• Bit-ops ! Field accesses
if (p.rd == 0){
pte.idx = p.idx;
b.addr = tab[pte.idx].addr;
o.addr = p.addr;
return m[o.addr + p.addr];
Our approach: (2) Translation
p
pte
12 20
b
30 2
20 10 11
o
1020 2
p : {idx,20}{addr,10}{wr,1}{rd,1}
pte : {;,20}{idx,10}
b : {addr,30}{;,2}
o : {;,20}{addr,10}{;,2}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
mget (p) { if (p & 0x1 == 0){ error(“permission”); }
pte =(p & 0xFFFFF000)>>12;
b = tab[pte]& 0xFFFFFFFC;
o = p & 0xFFC;
return m[(b+o)>>2];}
• Expressions ! Records• Bit-ops ! Field accesses
if (p.rd == 0){
pte.idx = p.idx;
b.addr = tab[pte.idx].addr;
o.addr = p.addr;
return m[o.addr + p.addr];
Constraint SolutionsSolution is an assignment • A: variables ! bit-level typesA()[i:j] = subsequence of A() from bit i
through j
20 10 11
p)= {idx,20}{addr,10}{wr,1}{rd,1}
• A(p)[12:1] = {addr,10} {wr,1}
• A(p)[31:2] = {idx,20} {addr,10}
• A(p)[31:5] = undefined
12 131 25