# rsicv asm2cfg
最近在研究disassembly 再找有沒有實際可以把asm轉成cfg的tool
https://github.com/Kazhuu/asm2cfg
找到是找到了但是只支援single fucntion 和x86 和 arm
唯一比較有印象的是以前的ida pro
![](https://i.imgur.com/uuGnOwU.png)
今天下午有空來幫改一下,
在Development 他也有說到可以新建環境
https://github.com/x213212/asm2cfg
```bash=
pipenv install -d
pipenv shell
```
想離開開發環境就下
```bash=
exit
```
在環境中要使用改動的後的asm2cfg呢
```bash=
python -m src.asm2cfg -h
python -m src.asm2cfg -c examples/huge.asm
```
準備就緒就看一下大概改什麼
改動的地方為
# add riscv info
可以選擇架構兼容不同指令及架構我們抄arm 魔改一下
```python=
elif target_name == 'riscv':
target_info = riscvTargetInfo()
```
```python=
class riscvTargetInfo:
"""
Contains instruction info for riscv-compatible targets.
"""
def __init__(self):
pass
def comment(self):
return '#'
def is_call(self, instruction):
# print(instruction)
# Various flavors of call:
# call *0x26a16(%rip)
# call 0x555555555542
# addr32 call 0x55555558add0
return instruction.opcode in ('call')\
and instruction.opcode not in ('beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu')
def is_jump(self, instruction):
# print(instruction)
return instruction.opcode in ('j', 'jle', 'jl', 'je', 'jne', 'jge','je','jal') and not self.is_call(instruction)
# return instruction.opcode[0] == 'j'
# def is_jump2(self, instruction):
# return instruction.opcode[0] == 'jal'
def is_branch(self, instruction):
# print(instruction)
# Various flavors of call:
# call *0x26a16(%rip)
# call 0x555555555542
# addr32 call 0x55555558add0
return instruction.opcode in ('beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu')
def is_unconditional_jump(self, instruction):
return instruction.opcode.startswith('jmp')
def is_sink(self, instruction):
"""
Is this an instruction which terminates function execution e.g. return?
"""
return instruction.opcode.startswith('ret')
```
# parse_lines
在判斷指令後作者他會抓取inst的 ops這邊我們直接取,整個程式碼架構沒有耦合太嚴重,很好改
在add riscv info章節,增加那些fucntion就是為了判斷,遇到branch 或者jump 指令,看指令種類取出ops(address)
```py=
# Infer target address for jump instructions
for instruction in instructions:
print(instruction)
print(instruction.is_direct_jump2())
print(instruction.is_branch_1())
if (instruction.target is None or instruction.target.abs is None) \
and instruction.is_direct_jump():
if instruction.target is None:
instruction.target = Address(0)
instruction.target.abs = int(instruction.ops[0], 16)
if (instruction.target is None or instruction.target.abs is None) \
and instruction.is_direct_jump2():
if instruction.target is None:
instruction.target = Address(0)
instruction.target.abs = int(instruction.ops[1], 16)
if (instruction.target is None or instruction.target.abs is None) \
and instruction.is_branch_1():
if instruction.target is None:
instruction.target = Address(0)
instruction.target.abs = int(instruction.ops[2], 16)
```
# jump table
一樣增加 not inst.is_direct_jump2() 和 not inst.is_branch_1():
這邊我們就可以直接取到剛剛存進去的address
```python=
class JumpTable:
"""
Holds info about branch sources and destinations in asm function.
"""
def __init__(self, instructions):
# Address where the jump begins and value which address
# to jump to. This also includes calls.
self.abs_sources = {}
self.rel_sources = {}
# Addresses where jumps end inside the current function.
self.abs_destinations = set()
self.rel_destinations = set()
# Iterate over the lines and collect jump targets and branching points.
for inst in instructions:
if inst is None or not inst.is_direct_jump() and not inst.is_direct_jump2() \
and not inst.is_branch_1():
continue
# print(inst)
# print("=====================")
self.abs_sources[inst.address.abs] = inst.target
self.abs_destinations.add(inst.target.abs)
self.rel_sources[inst.address.offset] = inst.target
self.rel_destinations.add(inst.target.offset)
```
# build riscv & output objdump
寫一個c 然後用 riscv64-unknown-elf-gcc 進行編譯
```c=
#include <stdio.h>
int __attribute__((noinline)) test2 (int a){
a=a+1;
return a;
}
int main(){
int test =10;
printf("%d\n",test);
printf("%d\n",test2(test));
int k ;
if(k > 10)
printf("%d\n",test2(test));
else
printf("%d\n",test);
return 0;
}
```
```bash=
riscv64-unknown-elf-gcc test.c
riscv64-unknown-elf-objdump -d ./a.out | sed -ne '/<main/,/^$/p' > a.asm
```
分別取出片段
# a.asm
```asm=
000000000001016e <main>:
1016e: 1101 addi sp,sp,-32
10170: ec06 sd ra,24(sp)
10172: e822 sd s0,16(sp)
10174: 1000 addi s0,sp,32
10176: 47a9 li a5,10
10178: fef42623 sw a5,-20(s0)
1017c: fec42783 lw a5,-20(s0)
10180: 85be mv a1,a5
10182: 67f1 lui a5,0x1c
10184: 2d078513 addi a0,a5,720 # 1c2d0 <__clzdi2+0x3a>
10188: 1b4000ef jal ra,1033c <printf>
1018c: fec42783 lw a5,-20(s0)
10190: 853e mv a0,a5
10192: fbbff0ef jal ra,1014c <test2>
10196: 87aa mv a5,a0
10198: 85be mv a1,a5
1019a: 67f1 lui a5,0x1c
1019c: 2d078513 addi a0,a5,720 # 1c2d0 <__clzdi2+0x3a>
101a0: 19c000ef jal ra,1033c <printf>
101a4: fe842783 lw a5,-24(s0)
101a8: 0007871b sext.w a4,a5
101ac: 47a9 li a5,10
101ae: 00e7df63 bge a5,a4,101cc <main+0x5e>
101b2: fec42783 lw a5,-20(s0)
101b6: 853e mv a0,a5
101b8: f95ff0ef jal ra,1014c <test2>
101bc: 87aa mv a5,a0
101be: 85be mv a1,a5
101c0: 67f1 lui a5,0x1c
101c2: 2d078513 addi a0,a5,720 # 1c2d0 <__clzdi2+0x3a>
101c6: 176000ef jal ra,1033c <printf>
101ca: a809 j 101dc <main+0x6e>
101cc: fec42783 lw a5,-20(s0)
101d0: 85be mv a1,a5
101d2: 67f1 lui a5,0x1c
101d4: 2d078513 addi a0,a5,720 # 1c2d0 <__clzdi2+0x3a>
101d8: 164000ef jal ra,1033c <printf>
101dc: 4781 li a5,0
101de: 853e mv a0,a5
101e0: 60e2 ld ra,24(sp)
101e2: 6442 ld s0,16(sp)
101e4: 6105 addi sp,sp,32
101e6: 8082 ret
```
# a2.asm
```asm=
000000000001014c <test2>:
1014c: 1101 addi sp,sp,-32
1014e: ec22 sd s0,24(sp)
10150: 1000 addi s0,sp,32
10152: 87aa mv a5,a0
10154: fef42623 sw a5,-20(s0)
10158: fec42783 lw a5,-20(s0)
1015c: 2785 addiw a5,a5,1
1015e: fef42623 sw a5,-20(s0)
10162: fec42783 lw a5,-20(s0)
101c2: 2d078513 addi a0,a5,720 # 1c2d0 <__clzdi2+0x3a>
101c6: 176000ef jal ra,1033c <printf>
10166: 853e mv a0,a5
10168: 6462 ld s0,22(sp)
1016a: 6105 addi sp,sp,32
1016c: 8082 ret
```
a2.asm 我多加了
```asm=
101c2: 2d078513 addi a0,a5,720 # 1c2d0 <__clzdi2+0x3a>
101c6: 176000ef jal ra,1033c <printf>
```
這從a.asm搬過來的,為了測試graphiz是否能產生分支
# command_line.py
最後避免過度耦合,先不考慮合併的情況,作者說不能支持多個fucntion ,其實對於graphiz 來說只要共用同一個節點,線就會自動連上。
```python=
"""
Command-line usage support.
"""
import argparse
from . import asm2cfg
def main():
""" Command-line entry point to the program. """
parser = argparse.ArgumentParser(
description='Program to draw dot control-flow graph from GDB disassembly for a function.',
epilog='If function CFG rendering takes too long, try to skip function calls with -c flag.'
)
parser.add_argument('assembly_file',
help='File to contain one function assembly dump')
parser.add_argument('-c', '--skip-calls', action='store_true',
help='Skip function calls from dividing code to blocks')
parser.add_argument('--target', choices=['x86', 'arm','riscv'], default='riscv',
help='Specify target platform for assembly')
parser.add_argument('-v', '--view', action='store_true',
help='View as a dot graph instead of saving to a file')
args = parser.parse_args()
print('If function CFG rendering takes too long, try to skip function calls with -c flag')
lines = asm2cfg.read_lines(args.assembly_file)
function_name, basic_blocks = asm2cfg.parse_lines(lines, args.skip_calls, args.target)
lines2 = asm2cfg.read_lines("/root/asm2cfg/a2.asm")
function_name2, basic_blocks2 = asm2cfg.parse_lines(lines2, args.skip_calls, args.target)
asm2cfg.draw_cfg(function_name, basic_blocks,function_name2, basic_blocks2, args.view)
```
# draw_cfg
```py
def draw_cfg(function_name, basic_blocks,function_name2, basic_blocks2, view):
dot = Digraph(name=function_name, comment=function_name, engine='dot')
dot.attr('graph', label=function_name)
for address, basic_block in basic_blocks.items():
key = str(address)
dot.node(key, shape='record', label=basic_block.get_label())
for basic_block in basic_blocks.values():
if basic_block.jump_edge:
if basic_block.no_jump_edge is not None:
dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))
elif basic_block.no_jump_edge:
dot.edge(str(basic_block.key), str(basic_block.no_jump_edge))
# dot.attr('graph', label=function_name2)
for address, basic_block in basic_blocks2.items():
key = str(address)
dot.node(key, shape='record', label=basic_block.get_label())
for basic_block in basic_blocks2.values():
if basic_block.jump_edge:
if basic_block.no_jump_edge is not None:
dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))
elif basic_block.no_jump_edge:
dot.edge(str(basic_block.key), str(basic_block.no_jump_edge))
# if view:
dot.format = 'png'
with tempfile.NamedTemporaryFile(mode='w+b', prefix=function_name) as filename:
dot.view(filename.name)
print(f'Opening a file {filename.name}.{dot.format} with default viewer. Don\'t forget to delete it later.')
# else:
# dot.format = 'pdf'
# dot.render(filename=function_name, cleanup=True)
# print(f'Saved CFG to a file {function_name}.{dot.format}')
```
# output graphiz
```bash=
python -m src.asm2cfg ./a.asm
```
![](https://i.imgur.com/pEZIAaQ.png)
為的就是直接在markdown顯示
```graphviz
digraph main {
graph [bb="0,0,933.5,1333",
label=main,
lheight=0.21,
lp="466.75,11.5",
lwidth=0.50
];
node [label="\N"];
65902 [height=2.7361,
label="{addi sp,sp,-32\lsd ra,24(sp)\lsd s0,16(sp)\laddi s0,sp,32\lli a5,10\lsw a5,-20(s0)\llw a5,-20(s0)\lmv a1,a5\llui a5,0x1c\laddi \
a0,a5,720 # 1c2d0 \<__clzdi2+0x3a\>\ljal ra,1033c \<printf\>\l|{<s0>No Jump|<s1>Jump}}",
pos="775,1234.5",
rects="616.5,1159.5,933.5,1332.5 616.5,1136.5,787.5,1159.5 787.5,1136.5,933.5,1159.5",
shape=record,
width=4.4028];
65932 [height=1.0694,
label="{lw a5,-20(s0)\lmv a0,a5\ljal ra,1014c \<test2\>\l|{<s0>No Jump|<s1>Jump}}",
pos="702,1061.5",
rects="618.5,1046.5,785.5,1099.5 618.5,1023.5,714.5,1046.5 714.5,1023.5,785.5,1046.5",
shape=record,
width=2.3194];
65902:s0 -> 65932 [pos="e,702,1099.5 702,1136 702,1127.5 702,1118.4 702,1109.6"];
66364 [height=0.5,
pos="684,72.5",
width=1.1193];
65902:s1 -> 66364 [pos="e,703.96,88.406 861,1136 861,1046.4 861,1024.1 861,934.5 861,934.5 861,934.5 861,334.5 861,229.48 761.62,135.3 711.8,94.685"];
65942 [height=1.4861,
label="{mv a5,a0\lmv a1,a5\llui a5,0x1c\laddi a0,a5,720 # 1c2d0 \<__clzdi2+0x3a\>\ljal ra,1033c \<printf\>\l|{<s0>No Jump|<s1>Jump}}",
pos="636,933.5",
rects="477.5,903.5,794.5,986.5 477.5,880.5,648.5,903.5 648.5,880.5,794.5,903.5",
shape=record,
width=4.4028];
65932:s0 -> 65942 [pos="e,659.93,986.89 666,1023 666,1014.3 664.68,1005.3 662.59,996.6"];
65868 [height=2.7361,
label="{addi sp,sp,-32\lsd s0,24(sp)\laddi s0,sp,32\lmv a5,a0\lsw a5,-20(s0)\llw a5,-20(s0)\laddiw a5,a5,1\lsw a5,-20(s0)\llw a5,-20(s0)\laddi \
a0,a5,720 # 1c2d0 \<__clzdi2+0x3a\>\ljal ra,1033c \<printf\>\l|{<s0>No Jump|<s1>Jump}}",
pos="598,504.5",
rects="439.5,429.5,756.5,602.5 439.5,406.5,610.5,429.5 610.5,406.5,756.5,429.5",
shape=record,
width=4.4028];
65932:s1 -> 65868 [pos="e,669.34,602.59 787,1034.5 833.47,1034.5 820.49,944.2 804,880 778.94,782.45 722.54,683.06 675.09,611.21"];
65956 [height=1.2778,
label="{lw a5,-24(s0)\lsext.w a4,a5\lli a5,10\lbge a5,a4,101cc \<main+0x5e\>\l|{<s0>No Jump|<s1>Jump}}",
pos="350,798",
rects="228.5,775.5,471.5,843.5 228.5,752.5,362.5,775.5 362.5,752.5,471.5,775.5",
shape=record,
width=3.375];
65942:s0 -> 65956 [pos="e,385.36,843.62 476,891.5 444.06,891.5 414.86,871.95 392.63,850.82"];
65942:s1 -> 66364 [pos="e,695.39,90.041 796,891.5 807.85,891.5 785,690.35 785,678.5 785,678.5 785,678.5 785,334.5 785,242.45 729.69,143.71 700.93,98.584"];
65970 [height=1.0694,
label="{lw a5,-20(s0)\lmv a0,a5\ljal ra,1014c \<test2\>\l|{<s0>No Jump|<s1>Jump}}",
pos="295,677.5",
rects="211.5,662.5,378.5,715.5 211.5,639.5,307.5,662.5 307.5,639.5,378.5,662.5",
shape=record,
width=2.3194];
65956:s0 -> 65970 [pos="e,295,715.51 295,752 295,743.47 295,734.38 295,725.61"];
65996 [height=1.4861,
label="{lw a5,-20(s0)\lmv a1,a5\llui a5,0x1c\laddi a0,a5,720 # 1c2d0 \<__clzdi2+0x3a\>\ljal ra,1033c \<printf\>\l|{<s0>No Jump|<s1>Jump}}",
pos="186,211.5",
rects="27.5,181.5,344.5,264.5 27.5,158.5,198.5,181.5 198.5,158.5,344.5,181.5",
shape=record,
width=4.4028];
65956:s1 -> 65996 [pos="e,265.87,264.54 417,752 417,597.82 458.28,545.2 392,406 366.03,351.47 317.41,304.64 273.93,270.72"];
65980 [height=1.4861,
label="{mv a5,a0\lmv a1,a5\llui a5,0x1c\laddi a0,a5,720 # 1c2d0 \<__clzdi2+0x3a\>\ljal ra,1033c \<printf\>\l|{<s0>No Jump|<s1>Jump}}",
pos="224,504.5",
rects="65.5,474.5,382.5,557.5 65.5,451.5,236.5,474.5 236.5,451.5,382.5,474.5",
shape=record,
width=4.4028];
65970:s0 -> 65980 [pos="e,244.26,557.63 259,639 259,615.1 253.69,589.56 247.2,567.28"];
65970:s1 -> 65868 [pos="e,502.83,602.62 380,650.5 421.27,650.5 460.7,632.26 494.39,608.71"];
65994 [height=0.65278,
label="{j 101dc \<main+0x6e\>\l|{<s0>No Jump|<s1>Jump}}",
pos="151,335.5",
rects="61.5,335.5,240.5,358.5 61.5,312.5,163.5,335.5 163.5,312.5,240.5,335.5",
shape=record,
width=2.4861];
65980:s0 -> 65994 [pos="e,151,358.78 151,450.5 151,422.99 151,391.75 151,368.94"];
65980:s1 -> 66364 [pos="e,665.32,88.597 384,462.5 423.66,462.5 437.32,333.54 460,301 519.53,215.6 612.27,133.06 657.46,95.147"];
65994:s0 -> 65996 [pos="e,128.79,264.72 112,311.5 112,297.99 116.47,285.14 123.22,273.44"];
66012 [height=1.375,
label="{li a5,0\lmv a0,a5\lld ra,24(sp)\lld s0,16(sp)\laddi sp,sp,32\lret\l}",
pos="56,72.5",
rects="0,23.5,112,121.5",
shape=record,
width=1.5556];
65994:s1 -> 66012 [pos="e,27.022,121.68 202,311.5 202,227.15 69.824,331.55 18,265 -11.622,226.96 3.4056,172.07 22.61,130.8"];
65996:s0 -> 66012 [pos="e,32.498,121.78 26,169.5 16.347,169.5 20.628,151.59 28.608,131.25"];
65996:s1 -> 66364 [pos="e,645.35,77.631 346,169.5 353.71,169.5 352.19,161.63 359,158 449.61,109.75 569.33,87.899 635.24,78.957"];
65868:s1 -> 66364 [pos="e,684,90.807 684,406 684,292.89 684,158.15 684,101.14"];
65894 [height=0.95833,
label="{mv a0,a5\lld s0,22(sp)\laddi sp,sp,32\lret\l}",
pos="525,335.5",
rects="469,301.5,581,369.5",
shape=record,
width=1.5556];
65868:s0 -> 65894 [pos="e,525,369.73 525,406 525,397.59 525,388.61 525,380"];
}
```
輸出png也是ok的
/tmp/main8ttsp644.png
![](https://i.imgur.com/z2OTTAb.png)
![](https://i.imgur.com/AyO6MKJ.png)
指向66364原因就是找不到printf的程式碼無法產生節點
其中要撈取程式碼,
```bash=
root@HOME-X213212:~/asm2cfg# gcc test.c
root@HOME-X213212:~/asm2cfg# gdb -batch -ex 'info functions' ./a.out
All defined functions:
Non-debugging symbols:
0x0000000000001000 _init
0x0000000000001030 printf@plt
0x0000000000001040 __cxa_finalize@plt
0x0000000000001050 _start
0x0000000000001080 deregister_tm_clones
0x00000000000010c0 register_tm_clones
0x0000000000001110 __do_global_dtors_aux
0x0000000000001150 frame_dummy
0x000000000000115a test2
0x000000000000116a main
0x00000000000011f0 __libc_csu_init
0x0000000000001260 __libc_csu_fini
0x0000000000001268 _fini
```
這邊用這種方式也可以撈取,沒用riscv64-unknown-elf-gdb因為我少lib,老樣子如果靜態連結的話要畫出graphiz的圖可能會當機,到這邊我們就達到ida pro ide的大致樣子了
# 後記
測了個switch
```c
int main(){
int number;
switch (number) {
case 10:
printf("number is equals to 10\n");
break;
case 50:
printf("number is equal to 50\n");
break;
case 100:
printf("number is equal to 100\n");
break;
default:
printf("number is not equal to 10, 50 or 100\n");
}
return 0;
}
```
```graphviz
digraph main {
graph [bb="0,0,892.5,1523",
label=main,
lheight=0.21,
lp="446.25,11.5",
lwidth=0.50
];
node [label="\N"];
65900 [height=2.1111,
label="{addi sp,sp,-32\lsd ra,24(sp)\lsd s0,16(sp)\laddi s0,sp,32\llw a5,-20(s0)\lsext.w a4,a5\lli a5,100\lbeq a4,a5,101cc \<main+0x60\>\l|{<\
s0>No Jump|<s1>Jump}}",
pos="435,1424.5",
rects="313,1372,557,1500 313,1349,447,1372 447,1349,557,1372",
shape=record,
width=3.3889];
65924 [height=1.2778,
label="{lw a5,-20(s0)\lsext.w a4,a5\lli a5,100\lblt a5,a4,101d8 \<main+0x6c\>\l|{<s0>No Jump|<s1>Jump}}",
pos="367,1244",
rects="247.5,1221.5,486.5,1289.5 247.5,1198.5,379.5,1221.5 379.5,1198.5,486.5,1221.5",
shape=record,
width=3.3194];
65900:s0 -> 65924 [pos="e,375.16,1289.7 380,1347.5 380,1332.1 378.53,1315.4 376.58,1300.1"];
65996 [height=1.0694,
label="{lui a5,0x12\laddi a0,a5,1728 # 126c0 \<__errno+0x3c\>\ljal ra,1039e \<puts\>\l|{<s0>No Jump|<s1>Jump}}",
pos="504,392.5",
rects="342.5,377.5,665.5,430.5 342.5,354.5,516.5,377.5 516.5,354.5,665.5,377.5",
shape=record,
width=4.4861];
65900:s1 -> 65996 [pos="e,507.36,430.66 502,1347.5 502,1244.9 515,1219.6 515,1117 515,1117 515,1117 515,587.5 515,537.33 511.29,479.99 508.18,440.73"];
65940 [height=1.2778,
label="{lw a5,-20(s0)\lsext.w a4,a5\lli a5,10\lbeq a4,a5,101b4 \<main+0x48\>\l|{<s0>No Jump|<s1>Jump}}",
pos="304,1116",
rects="180.5,1093.5,427.5,1161.5 180.5,1070.5,316.5,1093.5 316.5,1070.5,427.5,1093.5",
shape=record,
width=3.4306];
65924:s0 -> 65940 [pos="e,310.78,1161.9 313,1198 313,1189.6 312.51,1180.7 311.76,1172"];
66008 [height=1.0694,
label="{lui a5,0x12\laddi a0,a5,1752 # 126d8 \<__errno+0x54\>\ljal ra,1039e \<puts\>\l|{<s0>No Jump|<s1>Jump}}",
pos="259,196.5",
rects="96,181.5,422,234.5 96,158.5,271,181.5 271,158.5,422,181.5",
shape=record,
width=4.5278];
65924:s1 -> 66008 [pos="e,265.57,234.73 433,1198 433,1150.5 477,1036.5 477,989 477,989 477,989 477,587.5 477,492.98 380.4,512.77 333,431 298.45,371.41 278,\
293.75 267.63,244.74"];
65954 [height=1.2778,
label="{lw a5,-20(s0)\lsext.w a4,a5\lli a5,50\lbeq a4,a5,101c0 \<main+0x54\>\l|{<s0>No Jump|<s1>Jump}}",
pos="221,988",
rects="98.5,965.5,343.5,1033.5 98.5,942.5,233.5,965.5 233.5,942.5,343.5,965.5",
shape=record,
width=3.4028];
65940:s0 -> 65954 [pos="e,241.46,1033.5 248,1070 248,1061.2 246.54,1052.1 244.29,1043.3"];
65972 [height=1.0694,
label="{lui a5,0x12\laddi a0,a5,1680 # 12690 \<__errno+0xc\>\ljal ra,1039e \<puts\>\l|{<s0>No Jump|<s1>Jump}}",
pos="224,784.5",
rects="66.5,769.5,381.5,822.5 66.5,746.5,236.5,769.5 236.5,746.5,381.5,769.5",
shape=record,
width=4.375];
65940:s1 -> 65972 [pos="e,264.22,822.66 372,1070 372,1012.4 375.49,994.57 352,942 332.99,899.46 299.27,858.96 271.22,829.81"];
65970 [height=0.65278,
label="{j 101d8 \<main+0x6c\>\l|{<s0>No Jump|<s1>Jump}}",
pos="166,882.5",
rects="76,882.5,256,905.5 76,859.5,178,882.5 178,859.5,256,882.5",
shape=record,
width=2.5];
65954:s0 -> 65970 [pos="e,166,905.72 166,942 166,933.57 166,924.46 166,916"];
65984 [height=1.0694,
label="{lui a5,0x12\laddi a0,a5,1704 # 126a8 \<__errno+0x24\>\ljal ra,1039e \<puts\>\l|{<s0>No Jump|<s1>Jump}}",
pos="230,588.5",
rects="67.5,573.5,392.5,626.5 67.5,550.5,242.5,573.5 242.5,550.5,392.5,573.5",
shape=record,
width=4.5139];
65954:s1 -> 65984 [pos="e,286.99,626.79 345,954 439.58,954 426.68,833.18 390,746 370.68,700.08 330.58,660.9 295.35,633.22"];
65970:s0 -> 65972 [pos="e,144.34,822.52 127,859 127,847.95 131.05,838.35 137.49,830.07"];
65970:s1 -> 66008 [pos="e,221.48,234.73 217,859 217,786.11 106.38,876.61 57,823 15.799,778.27 38,748.31 38,687.5 38,687.5 38,687.5 38,587.5 38,533.28 35.897,\
516.94 57,467 94.451,378.37 167.22,292.33 214.42,242.17"];
65982 [height=0.65278,
label="{j 101e2 \<main+0x76\>\l|{<s0>No Jump|<s1>Jump}}",
pos="157,686.5",
rects="66.5,686.5,247.5,709.5 66.5,663.5,169.5,686.5 169.5,663.5,247.5,686.5",
shape=record,
width=2.5139];
65972:s0 -> 65982 [pos="e,153.65,709.67 151,746 151,737.44 151.64,728.2 152.51,719.66"];
66462 [height=0.5,
pos="545,72.5",
width=1.1193];
65972:s1 -> 66462 [pos="e,559.38,89.626 383,757.5 438.03,757.5 426.66,704.32 463,663 555.25,558.12 624.47,561.22 675,431 723.39,306.3 613.84,155.14 565.97,\
97.446"];
65982:s0 -> 65984 [pos="e,135.01,626.85 118,663 118,652.01 121.82,642.57 128.04,634.49"];
66018 [height=1.375,
label="{li a5,0\lmv a0,a5\lld ra,24(sp)\lld s0,16(sp)\laddi sp,sp,32\lret\l}",
pos="111,72.5",
rects="55,23.5,167,121.5",
shape=record,
width=1.5556];
65982:s1 -> 66018 [pos="e,70.298,121.57 209,663 209,594.01 110.76,671.46 58,627 7.9055,584.79 0,557.01 0,491.5 0,491.5 0,491.5 0,293.5 0,232.94 33.942,172.08 \
64.288,129.78"];
65994 [height=0.65278,
label="{j 101e2 \<main+0x76\>\l|{<s0>No Jump|<s1>Jump}}",
pos="157,490.5",
rects="66.5,490.5,247.5,513.5 66.5,467.5,169.5,490.5 169.5,467.5,247.5,490.5",
shape=record,
width=2.5139];
65984:s0 -> 65994 [pos="e,155.88,513.72 155,550 155,541.47 155.21,532.26 155.5,523.71"];
65984:s1 -> 66462 [pos="e,547.35,90.547 318,550 318,462.63 275.69,419.94 333,354 381.96,297.68 444.82,371.35 497,318 555.05,258.65 553.04,150.87 548.39,\
100.63"];
65994:s0 -> 65996 [pos="e,342.26,395.45 118,467 118,420.17 229.04,402.43 332,396.05"];
65994:s1 -> 66018 [pos="e,94.131,121.66 209,467 209,350.5 114.93,348.1 87,235 78.631,201.1 83.871,162.44 91.562,131.44"];
66006 [height=0.65278,
label="{j 101e2 \<main+0x76\>\l|{<s0>No Jump|<s1>Jump}}",
pos="398,294.5",
rects="307.5,294.5,488.5,317.5 307.5,271.5,410.5,294.5 410.5,271.5,488.5,294.5",
shape=record,
width=2.5139];
65996:s0 -> 66006 [pos="e,416.21,317.71 429,354 429,344.46 425.74,334.96 421.34,326.47"];
65996:s1 -> 66462 [pos="e,549.75,90.417 591,354 591,259.75 565.4,150.01 552.39,100.35"];
66006:s0 -> 66008 [pos="e,275.81,234.53 306,282.5 300.92,282.5 290.2,263.66 280.28,243.71"];
66006:s1 -> 66018 [pos="e,167.26,80.967 450,271 450,220.07 465.32,195.62 431,158 397.18,120.93 260.57,95.113 177.16,82.446"];
66008:s0 -> 66018 [pos="e,86.669,121.78 95,169.5 76.318,169.5 76.758,151.59 83.288,131.25"];
66008:s1 -> 66462 [pos="e,534.47,90.222 423,169.5 468.92,169.5 507.75,126.98 528.6,98.535"];
65868 [height=2.7361,
label="{addi sp,sp,-32\lsd s0,24(sp)\laddi s0,sp,32\lmv a5,a0\lsw a5,-20(s0)\llw a5,-20(s0)\laddiw a5,a5,1\lsw a5,-20(s0)\llw a5,-20(s0)\laddi \
a0,a5,720 # 1c2d0 \<__clzdi2+0x3a\>\ljal ra,1033c \<printf\>\l|{<s0>No Jump|<s1>Jump}}",
pos="734,1424.5",
rects="575.5,1349.5,892.5,1522.5 575.5,1326.5,746.5,1349.5 746.5,1326.5,892.5,1349.5",
shape=record,
width=4.4028];
65894 [height=0.95833,
label="{mv a0,a5\lld s0,22(sp)\laddi sp,sp,32\lret\l}",
pos="661,1244",
rects="605,1210,717,1278",
shape=record,
width=1.5556];
65868:s0 -> 65894 [pos="e,661,1278.1 661,1326 661,1313.8 661,1300.6 661,1288.5"];
66364 [height=0.5,
pos="820,1244",
width=1.1193];
65868:s1 -> 66364 [pos="e,820,1262.1 820,1326 820,1308.1 820,1287.9 820,1272.2"];
}
```
太神拉,我們完成了!