Module是指模块,Function模块下的函数,BasicBlock函数下的基本块,Instruction 基本块下的IR指令
1
2
3
4
5
6
7
8
9
|
for
(Function::iterator i
=
f
-
>begin(); i !
=
f
-
>end();
+
+
i) {
BasicBlock
*
tmp
=
&
*
i;
origBB.push_back(tmp);
BasicBlock
*
bb
=
&
*
i;
if
(isa<InvokeInst>(bb
-
>getTerminator())) {
return
false;
}
}
|
把函数分成很多个基本块,并且push到vector类型的 origBB中。
判断里面基本块是否大于1,不大于1的话就没有意义去进行混淆:
1
2
3
|
if
(origBB.size() <
=
1
) {
return
false;
}
|
需要把vertor里面的第一个基本块即入口基本块单独拿出来进行处理:对入口基本块进行判断,如果是无条件跳转则不进行任何处理,否则需要找到最后一条指令,将整个if结构给split,split之后两个块之间会自动添加跳转指令,然后就可以把原来的split后的if结构给它扔进要处理的基本块列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
origBB.erase(origBB.begin());
/
/
Get a pointer on the first BB
Function::iterator tmp
=
f
-
>begin();
/
/
+
+
tmp;
BasicBlock
*
insert
=
&
*
tmp;
/
/
If main begin with an
if
BranchInst
*
br
=
NULL;
if
(isa<BranchInst>(insert
-
>getTerminator())) {
br
=
cast<BranchInst>(insert
-
>getTerminator());
}
if
((br !
=
NULL && br
-
>isConditional()) ||
insert
-
>getTerminator()
-
>getNumSuccessors() >
1
) {
BasicBlock::iterator i
=
insert
-
>end();
-
-
i;
if
(insert
-
>size() >
1
) {
-
-
i;
}
BasicBlock
*
tmpBB
=
insert
-
>splitBasicBlock(i,
"first"
);
origBB.insert(origBB.begin(), tmpBB);
}
|
如果是条件跳转的话这里是把上面自动添加那个跳转指令给删除,如果不是的话,那么也是需要把它删除,因为跳转点目标还不能确定:
1
2
|
/
/
Remove jump
insert
-
>getTerminator()
-
>eraseFromParent();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
%
retval
=
alloca i32, align
4
%
argc.addr
=
alloca i32, align
4
%
argv.addr
=
alloca i8
*
*
, align
8
%
a
=
alloca i32, align
4
store i32
0
, i32
*
%
retval, align
4
store i32
%
argc, i32
*
%
argc.addr, align
4
store i8
*
*
%
argv, i8
*
*
*
%
argv.addr, align
8
%
0
=
load i8
*
*
, i8
*
*
*
%
argv.addr, align
8
%
arrayidx
=
getelementptr inbounds i8
*
, i8
*
*
%
0
, i64
1
%
1
=
load i8
*
, i8
*
*
%
arrayidx, align
8
%
call
=
call i32 @atoi(i8
*
%
1
)
#3
store i32
%
call, i32
*
%
a, align
4
%
2
=
load i32, i32
*
%
a, align
4
br label
%
NodeBlock8
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
entry:
%
.reg2mem
=
alloca i32
%
retval
=
alloca i32, align
4
%
argc.addr
=
alloca i32, align
4
%
argv.addr
=
alloca i8
*
*
, align
8
%
a
=
alloca i32, align
4
store i32
0
, i32
*
%
retval, align
4
store i32
%
argc, i32
*
%
argc.addr, align
4
store i8
*
*
%
argv, i8
*
*
*
%
argv.addr, align
8
%
0
=
load i8
*
*
, i8
*
*
*
%
argv.addr, align
8
%
arrayidx
=
getelementptr inbounds i8
*
, i8
*
*
%
0
, i64
1
%
1
=
load i8
*
, i8
*
*
%
arrayidx, align
8
%
call
=
call i32 @atoi(i8
*
%
1
)
#3
store i32
%
call, i32
*
%
a, align
4
%
2
=
load i32, i32
*
%
a, align
4
store i32
%
2
, i32
*
%
.reg2mem
%
switchVar
=
alloca i32
|
创建一个switchvar变量,然后去获取一个随机整数创建store指令塞给switchvar中
1
2
3
4
5
6
|
switchVar
=
new AllocaInst(
Type
::getInt32Ty(f
-
>getContext()),
0
,
"switchVar"
, insert);
new StoreInst(
ConstantInt::get(
Type
::getInt32Ty(f
-
>getContext()),
llvm::cryptoutils
-
>scramble32(
0
, scrambling_key)),
switchVar, insert);
|
也就是在switchvar添了如下这一行:
1
|
store i32
157301900
, i32
*
%
switchVar
|
创建两个block,其它的基本块插入它们之间
1
2
|
loopEntry
=
BasicBlock::Create(f
-
>getContext(),
"loopEntry"
, f, insert);
loopEnd
=
BasicBlock::Create(f
-
>getContext(),
"loopEnd"
, f, insert);
|
如下:
1
2
3
|
loopEntry:
loopEnd:
|
目标基本块里面啥内容也没有。
在loopEntry里面新建一个load指令,并且把switchVar:
1
|
load
=
new LoadInst(switchVar,
"switchVar"
, loopEntry);
|
目前loopentry指令如下:
1
2
|
loopEntry: ; preds
=
%
entry,
%
loopEnd
%
switchVar10
=
load i32, i32
*
%
switchVar
|
把insert插入到loopEntry之前,这里的insert就是entry基本块,再创建两个跳转指令,从insert(即第一个基本块)跳转到loopEntry;从loopend跳转到loopEntry:
1
2
3
4
5
|
/
/
Move first BB on top
insert
-
>moveBefore(loopEntry);
BranchInst::Create(loopEntry, insert);
/
/
loopEnd jump to loopEntry
BranchInst::Create(loopEntry, loopEnd);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
entry:
%
.reg2mem
=
alloca i32
%
retval
=
alloca i32, align
4
%
argc.addr
=
alloca i32, align
4
%
argv.addr
=
alloca i8
*
*
, align
8
%
a
=
alloca i32, align
4
store i32
0
, i32
*
%
retval, align
4
store i32
%
argc, i32
*
%
argc.addr, align
4
store i8
*
*
%
argv, i8
*
*
*
%
argv.addr, align
8
%
0
=
load i8
*
*
, i8
*
*
*
%
argv.addr, align
8
%
arrayidx
=
getelementptr inbounds i8
*
, i8
*
*
%
0
, i64
1
%
1
=
load i8
*
, i8
*
*
%
arrayidx, align
8
%
call
=
call i32 @atoi(i8
*
%
1
)
#3
store i32
%
call, i32
*
%
a, align
4
%
2
=
load i32, i32
*
%
a, align
4
store i32
%
2
, i32
*
%
.reg2mem
%
switchVar
=
alloca i32
store i32
157301900
, i32
*
%
switchVar
br label
%
loopEntry
|
而loopend模块也有了一条指令(其实也是完整了):
1
2
|
loopEnd:
br label
%
loopEntry
|
紧接着创建一个基本块,然后在基本块里面创建一个跳转指令,从switchDefault跳转到loopend中:
1
2
3
|
BasicBlock
*
swDefault
=
BasicBlock::Create(f
-
>getContext(),
"switchDefault"
, f, loopEnd);
BranchInst::Create(loopEnd, swDefault);
|
多了一个switchDefault基本块,指令如下:
1
2
|
switchDefault: ; preds
=
%
loopEntry
br label
%
loopEnd
|
创建一个switch指令,位置是在loopentry基本块下,且创建了0个case,然后设置了条件为load,就上面的load。
1
2
|
switchI
=
SwitchInst::Create(&
*
f
-
>begin(), swDefault,
0
, loopEntry);
switchI
-
>setCondition(load);
|
把entry最后一行跳转指令删除后再创建了一个跳转指令,从entry跳转到loopentry:
1
2
|
f
-
>begin()
-
>getTerminator()
-
>eraseFromParent();
BranchInst::Create(loopEntry, &
*
f
-
>begin());
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
for
(std::vector<BasicBlock
*
>::iterator b
=
origBB.begin();
b !
=
origBB.end();
+
+
b) {
BasicBlock
*
i
=
*
b;
ConstantInt
*
numCase
=
NULL;
/
/
Move the BB inside the switch (only visual, no code logic)
i
-
>moveBefore(loopEnd);
/
/
Add case to switch
numCase
=
cast<ConstantInt>(ConstantInt::get(
switchI
-
>getCondition()
-
>getType(),
llvm::cryptoutils
-
>scramble32(switchI
-
>getNumCases(), scrambling_key)));
switchI
-
>addCase(numCase, i);
}
|
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
|
entry:
%
.reg2mem
=
alloca i32
%
retval
=
alloca i32, align
4
%
argc.addr
=
alloca i32, align
4
%
argv.addr
=
alloca i8
*
*
, align
8
%
a
=
alloca i32, align
4
store i32
0
, i32
*
%
retval, align
4
store i32
%
argc, i32
*
%
argc.addr, align
4
store i8
*
*
%
argv, i8
*
*
*
%
argv.addr, align
8
%
0
=
load i8
*
*
, i8
*
*
*
%
argv.addr, align
8
%
arrayidx
=
getelementptr inbounds i8
*
, i8
*
*
%
0
, i64
1
%
1
=
load i8
*
, i8
*
*
%
arrayidx, align
8
%
call
=
call i32 @atoi(i8
*
%
1
)
#3
store i32
%
call, i32
*
%
a, align
4
%
2
=
load i32, i32
*
%
a, align
4
store i32
%
2
, i32
*
%
.reg2mem
%
switchVar
=
alloca i32
store i32
157301900
, i32
*
%
switchVar
br label
%
loopEntry
loopEntry:
%
switchVar10
=
load i32, i32
*
%
switchVar
switch i32
%
switchVar10, label
%
switchDefault [
]
switchDefault: ; preds
=
%
loopEntry
br label
%
loopEnd
loopEnd:
br label
%
loopEntry
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
for
(std::vector<BasicBlock
*
>::iterator b
=
origBB.begin();
b !
=
origBB.end();
+
+
b) {
BasicBlock
*
i
=
*
b;
ConstantInt
*
numCase
=
NULL;
/
/
Move the BB inside the switch (only visual, no code logic)
i
-
>moveBefore(loopEnd);
/
/
Add case to switch
numCase
=
cast<ConstantInt>(ConstantInt::get(
switchI
-
>getCondition()
-
>getType(),
llvm::cryptoutils
-
>scramble32(switchI
-
>getNumCases(), scrambling_key)));
switchI
-
>addCase(numCase, i);
}
|
这里的i就是指剩下的那些case分支代码基本块,i->moveBefore(loopEnd),把某个代码基本块置于loopend之前。比如某个基本块是这样:
1
2
3
|
NodeBlock8: ; preds
=
%
entry
%
Pivot9
=
icmp slt i32
%
2
,
2
br i1
%
Pivot9, label
%
LeafBlock, label
%
NodeBlock
|
然后下面的这些代码就是创建一个numcase,就是case分支里面的case值,这个值它是随机生成的,种子的话是Entry.cpp里面的那个AesSeed值,如果确定AesSeed的话,那么这里随机生成的case每次都是固定的。
switchI->addCase(numCase, i);紧接着在switch里面增加一个case值,跳转到NodeBlock8里面。
目前switch执行完一次后,loopentry基本bolck块如下:
1
2
3
4
5
|
loopEntry:
%
switchVar10
=
load i32, i32
*
%
switchVar
switch i32
%
switchVar10, label
%
switchDefault [
i32
157301900
, label
%
NodeBlock8
]
|
当循环执行结束后:
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
|
entry:
%
retval
=
alloca i32, align
4
%
argc.addr
=
alloca i32, align
4
%
argv.addr
=
alloca i8
*
*
, align
8
%
a
=
alloca i32, align
4
store i32
0
, i32
*
%
retval, align
4
store i32
%
argc, i32
*
%
argc.addr, align
4
store i8
*
*
%
argv, i8
*
*
*
%
argv.addr, align
8
%
0
=
load i8
*
*
, i8
*
*
*
%
argv.addr, align
8
%
arrayidx
=
getelementptr inbounds i8
*
, i8
*
*
%
0
, i64
1
%
1
=
load i8
*
, i8
*
*
%
arrayidx, align
8
%
call
=
call i32 @atoi(i8
*
%
1
)
#3
store i32
%
call, i32
*
%
a, align
4
%
2
=
load i32, i32
*
%
a, align
4
br label
%
NodeBlock8
NodeBlock8: ; preds
=
%
entry
%
Pivot9
=
icmp slt i32
%
2
,
2
br i1
%
Pivot9, label
%
LeafBlock, label
%
NodeBlock
NodeBlock: ; preds
=
%
NodeBlock8
%
Pivot
=
icmp slt i32
%
2
,
3
br i1
%
Pivot, label
%
sw.bb2, label
%
LeafBlock6
LeafBlock6: ; preds
=
%
NodeBlock
%
SwitchLeaf7
=
icmp eq i32
%
2
,
3
br i1
%
SwitchLeaf7, label
%
sw.bb4, label
%
NewDefault
LeafBlock: ; preds
=
%
NodeBlock8
%
SwitchLeaf
=
icmp eq i32
%
2
,
1
br i1
%
SwitchLeaf, label
%
sw.bb, label
%
NewDefault
sw.bb: ; preds
=
%
LeafBlock
%
call1
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
, i64
0
, i64
0
))
br label
%
sw.epilog
sw.bb2: ; preds
=
%
NodeBlock
%
call3
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
.
1
, i64
0
, i64
0
))
br label
%
sw.epilog
sw.bb4: ; preds
=
%
LeafBlock6
%
call5
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
.
2
, i64
0
, i64
0
))
br label
%
sw.epilog
NewDefault: ; preds
=
%
LeafBlock6,
%
LeafBlock
br label
%
sw.default
sw.default: ; preds
=
%
NewDefault
br label
%
sw.epilog
sw.epilog: ; preds
=
%
sw.default,
%
sw.bb4,
%
sw.bb2,
%
sw.bb
%
3
=
load i32, i32
*
%
a, align
4
%
cmp
=
icmp eq i32
%
3
,
0
br i1
%
cmp
, label
%
if
.then, label
%
if
.
else
if
.then: ; preds
=
%
sw.epilog
store i32
1
, i32
*
%
retval, align
4
br label
%
return
if
.
else
: ; preds
=
%
sw.epilog
store i32
10
, i32
*
%
retval, align
4
br label
%
return
return
: ; preds
=
%
if
.
else
,
%
if
.then
%
4
=
load i32, i32
*
%
retval, align
4
ret i32
%
4
loopEnd: ; preds
=
%
if
.
else
,
%
if
.then,
%
sw.epilog,
%
sw.default,
%
NewDefault,
%
sw.bb4,
%
sw.bb2,
%
sw.bb,
%
LeafBlock,
%
LeafBlock6,
%
NodeBlock,
%
NodeBlock8,
%
switchDefault
br label
%
loopEntry
}
|
1
2
3
4
|
/
/
Ret BB
if
(i
-
>getTerminator()
-
>getNumSuccessors()
=
=
0
) {
continue
;
}
|
getNumSuccessors是获取后续BB的个数,Ret BB后继BB为0个(判断分支),直接continue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/
/
If it's a non
-
conditional jump
if
(i
-
>getTerminator()
-
>getNumSuccessors()
=
=
1
) {
/
/
Get successor
and
delete terminator
BasicBlock
*
succ
=
i
-
>getTerminator()
-
>getSuccessor(
0
);
i
-
>getTerminator()
-
>eraseFromParent();
/
/
Get
next
case
numCase
=
switchI
-
>findCaseDest(succ);
/
/
If
next
case
=
=
default case (switchDefault)
if
(numCase
=
=
NULL) {
numCase
=
cast<ConstantInt>(
ConstantInt::get(switchI
-
>getCondition()
-
>getType(),
llvm::cryptoutils
-
>scramble32(
switchI
-
>getNumCases()
-
1
, scrambling_key)));
}
/
/
Update switchVar
and
jump to the end of loop
new StoreInst(numCase, load
-
>getPointerOperand(), i);
BranchInst::Create(loopEnd, i);
continue
;
}
|
如果后面只有一个分支的话,那么先判断分支是否能够找到,不为null后先去根据原来条件去创建一个store指令,然后创建一个跳转指令跳转到loopend,再把原来跳转指令抹去。
原来:
1
2
3
|
sw.bb: ; preds
=
%
LeafBlock
%
call1
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
, i64
0
, i64
0
))
br label
%
sw.epilog
|
改变后:
1
2
3
4
|
sw.bb: ; preds
=
%
LeafBlock
%
call1
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
, i64
0
, i64
0
))
store i32
387774014
, i32
*
%
switchVar
br label
%
loopEnd
|
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
|
if
(i
-
>getTerminator()
-
>getNumSuccessors()
=
=
2
) {
/
/
Get
next
cases
ConstantInt
*
numCaseTrue
=
switchI
-
>findCaseDest(i
-
>getTerminator()
-
>getSuccessor(
0
));
ConstantInt
*
numCaseFalse
=
switchI
-
>findCaseDest(i
-
>getTerminator()
-
>getSuccessor(
1
));
/
/
Check
if
next
case
=
=
default case (switchDefault)
if
(numCaseTrue
=
=
NULL) {
numCaseTrue
=
cast<ConstantInt>(
ConstantInt::get(switchI
-
>getCondition()
-
>getType(),
llvm::cryptoutils
-
>scramble32(
switchI
-
>getNumCases()
-
1
, scrambling_key)));
}
if
(numCaseFalse
=
=
NULL) {
numCaseFalse
=
cast<ConstantInt>(
ConstantInt::get(switchI
-
>getCondition()
-
>getType(),
llvm::cryptoutils
-
>scramble32(
switchI
-
>getNumCases()
-
1
, scrambling_key)));
}
/
/
Create a SelectInst
BranchInst
*
br
=
cast<BranchInst>(i
-
>getTerminator());
SelectInst
*
sel
=
SelectInst::Create(br
-
>getCondition(), numCaseTrue, numCaseFalse, "",
i
-
>getTerminator());
/
/
Erase terminator
i
-
>getTerminator()
-
>eraseFromParent();
/
/
Update switchVar
and
jump to the end of loop
new StoreInst(sel, load
-
>getPointerOperand(), i);
BranchInst::Create(loopEnd, i);
continue
;
}
|
首先会把两个跳转分支都取出来,先判断两个分支是否都能够找到,如果都不为null 的话,那么取出原来的跳转指令,根据br的两个分支条件,去创建一个SelectInst然后再删除原来指令,创建一个store指令,再去创建一个跳转指令跳转到loopend。
原来:
1
2
3
|
NodeBlock8: ; preds
=
%
entry
%
Pivot9
=
icmp slt i32
%
2
,
2
br i1
%
Pivot9, label
%
LeafBlock, label
%
NodeBlock
|
改变后:
1
2
3
4
5
|
NodeBlock8: ; preds
=
%
entry
%
Pivot9
=
icmp slt i32
%
2
,
2
%
3
=
select i1
%
Pivot9, i32
-
1519555718
, i32
241816174
store i32
%
3
, i32
*
%
switchVar
br label
%
loopEnd
|
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
|
define dso_local i32 @main(i32
%
argc, i8
*
*
%
argv)
#0 {
entry:
%
.reg2mem
=
alloca i32
%
retval
=
alloca i32, align
4
%
argc.addr
=
alloca i32, align
4
%
argv.addr
=
alloca i8
*
*
, align
8
%
a
=
alloca i32, align
4
store i32
0
, i32
*
%
retval, align
4
store i32
%
argc, i32
*
%
argc.addr, align
4
store i8
*
*
%
argv, i8
*
*
*
%
argv.addr, align
8
%
0
=
load i8
*
*
, i8
*
*
*
%
argv.addr, align
8
%
arrayidx
=
getelementptr inbounds i8
*
, i8
*
*
%
0
, i64
1
%
1
=
load i8
*
, i8
*
*
%
arrayidx, align
8
%
call
=
call i32 @atoi(i8
*
%
1
)
#3
store i32
%
call, i32
*
%
a, align
4
%
2
=
load i32, i32
*
%
a, align
4
store i32
%
2
, i32
*
%
.reg2mem
%
switchVar
=
alloca i32
store i32
157301900
, i32
*
%
switchVar
br label
%
loopEntry
loopEntry: ; preds
=
%
entry,
%
loopEnd
%
switchVar10
=
load i32, i32
*
%
switchVar
switch i32
%
switchVar10, label
%
switchDefault [
i32
157301900
, label
%
NodeBlock8
i32
241816174
, label
%
NodeBlock
i32
1003739776
, label
%
LeafBlock6
i32
-
1519555718
, label
%
LeafBlock
i32
-
749093422
, label
%
sw.bb
i32
1599617141
, label
%
sw.bb2
i32
1815329037
, label
%
sw.bb4
i32
1738940479
, label
%
NewDefault
i32
-
282945350
, label
%
sw.default
i32
387774014
, label
%
sw.epilog
i32
1681741611
, label
%
if
.then
i32
347219667
, label
%
if
.
else
i32
-
618048859
, label
%
return
]
switchDefault: ; preds
=
%
loopEntry
br label
%
loopEnd
NodeBlock8: ; preds
=
%
entry
%
Pivot9
=
icmp slt i32
%
2
,
2
%
3
=
select i1
%
Pivot9, i32
-
1519555718
, i32
241816174
store i32
%
3
, i32
*
%
switchVar
br label
%
loopEnd
NodeBlock: ; preds
=
%
NodeBlock8
%
Pivot
=
icmp slt i32
%
2
,
3
%
4
=
select i1
%
Pivot, i32
1599617141
, i32
1003739776
store i32
%
4
, i32
*
%
switchVar
br label
%
loopEnd
LeafBlock6: ; preds
=
%
NodeBlock
%
SwitchLeaf7
=
icmp eq i32
%
2
,
3
%
5
=
select i1
%
SwitchLeaf7, i32
1815329037
, i32
1738940479
store i32
%
5
, i32
*
%
switchVar
br label
%
loopEnd
LeafBlock: ; preds
=
%
NodeBlock8
%
SwitchLeaf
=
icmp eq i32
%
2
,
1
%
6
=
select i1
%
SwitchLeaf, i32
-
749093422
, i32
1738940479
store i32
%
6
, i32
*
%
switchVar
br label
%
loopEnd
sw.bb: ; preds
=
%
LeafBlock
%
call1
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
, i64
0
, i64
0
))
store i32
387774014
, i32
*
%
switchVar
br label
%
loopEnd
sw.bb2: ; preds
=
%
NodeBlock
%
call3
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
.
1
, i64
0
, i64
0
))
br label
%
sw.epilog
sw.bb4: ; preds
=
%
LeafBlock6
%
call5
=
call i32 (i8
*
, ...) @printf(i8
*
getelementptr inbounds ([
5
x i8], [
5
x i8]
*
@.
str
.
2
, i64
0
, i64
0
))
store i32
387774014
, i32
*
%
switchVar
br label
%
loopEnd
NewDefault: ; preds
=
%
LeafBlock6,
%
LeafBlock
br label
%
sw.default
sw.default: ; preds
=
%
NewDefault
store i32
387774014
, i32
*
%
switchVar
br label
%
loopEnd
sw.epilog: ; preds
=
%
sw.default,
%
sw.bb4,
%
sw.bb2,
%
sw.bb
%
3
=
load i32, i32
*
%
a, align
4
%
cmp
=
icmp eq i32
%
3
,
0
%
8
=
select i1
%
cmp
, i32
1681741611
, i32
347219667
store i32
%
8
, i32
*
%
switchVar
br label
%
loopEnd
if
.then: ; preds
=
%
sw.epilog
store i32
1
, i32
*
%
retval, align
4
store i32
-
618048859
, i32
*
%
switchVar
br label
%
loopEnd
if
.
else
: ; preds
=
%
sw.epilog
store i32
10
, i32
*
%
retval, align
4
store i32
-
618048859
, i32
*
%
switchVar
br label
%
loopEnd
return
: ; preds
=
%
if
.
else
,
%
if
.then
%
4
=
load i32, i32
*
%
retval, align
4
ret i32
%
4
loopEnd: ; preds
=
%
if
.
else
,
%
if
.then,
%
sw.epilog,
%
sw.default,
%
NewDefault,
%
sw.bb4,
%
sw.bb2,
%
sw.bb,
%
LeafBlock,
%
LeafBlock6,
%
NodeBlock,
%
NodeBlock8,
%
switchDefault
br label
%
loopEntry
}
|
附带一句,进行控制流平坦化之前刚开始会把switch语句给它全部进行改为if else目的主要是为了进行多次平坦化做准备(进行平坦化时里面是可以填次数)
正常流程就是首先进入entry,entry会给一个case常量值,然后进入loopentry,loopentry根据这个常量值进行switch分跳转到case常量对应的基本块,基本块执行完又会赋值一个case常量值,跳转到loopend,loopend又会跳转到loopentry进行下一次分发。(感觉特征点的话就是entry和loopend都会跳转到loopentry)。
大部分的方法都是基于定位loopend基本块,这种简单的IR结构编译成汇编代码也是这个样子,很容易定位到loopend基本块。在这里,我们的魔改方法就直接在loopend基本块后面加一个新的switchInst,然后跳转到基本块,相当于从开始的switch转移到后面来了。即抹除原来的跳转,插入loadInst加载swichvar,再用于swichInst跳转。
网上很多很多现成资料,我这个也是自己看了再总结的,如果哪里不对的话,还请多多指教。
更多【OLLVM控制流平坦化源码分析+魔改】相关视频教程:www.yxfzedu.com