计算机系统原理的实验,参考了我的前舍友和不知道哪位同学的博客,不过写得也太简略了并且还有一些错误,更像是单纯的记录,对手头没代码的人大概没啥意义吧。所以就把我自己做时的带注释的代码贴住来吧,也不过是记录罢了。
两位同学的博客:
MIPS - 反汇编 - 拆炸弹 - bomb(如你所见直接把标题抄过来了)
bomb二进制炸弹拆除实验(MIPS)
如果有同校学弟做实验时看到这篇博客,还是希望可以先尽量尝试独立完成,实在没办法时再来参考。如有错误,欢迎指正。
前导知识
gdb操作请看:GDB汇编调试指令合集
MIPS相关知识请看:MIPS指令集及汇编完全解析
开拆前…
本实验含有六个炸弹(和一个隐藏炸弹 ),在运行程序开头,需要输入ID(学号),在之后的拆弹过程中会使用到。每个炸弹都需要输入一行数据,包括数字或字符串。需避开一个个引爆点来通关。
阅读反汇编代码时,最好能够前后联系,理解数行/一部分代码的功能。要逐渐熟练掌握MIPS指令集操作和寄存器含义,了解数据存储的位置和方式。
有???标记的是我暂时抱有疑惑的地方,可以忽视。
本文还未完成,随缘更新。
phase_1
第一个炸弹,主要是熟悉用。炸弹会调用函数strings_not_equal来比较输入字符串与存储的字符串是否相等,不需要理解该子函数的实现,只需要明白该函数的功能即可。读寄存器$a1中保存的字符串,为“Let’s begin now!”,即为我们要输入的内容。
00400900 <main>:
...
400ba4: 8fdc0010 lw gp,16(s8)
400ba8: 0c1007fb jal 401fec <read_line> //读取输入
400bac: 00000000 nop
400bb0: 8fdc0010 lw gp,16(s8)
400bb4: afc20020 sw v0,32(s8) //将读得的数据存入栈
400bb8: 8fc40020 lw a0,32(s8) //并放入$a0中供函数phase_1使用
400bbc: 0c10035b jal 400d6c <phase_1>
...
00400d6c <phase_1>:
400d6c: 27bdffe0 addiu sp,sp,-32 //为当前函数开辟栈空间
400d70: afbf001c sw ra,28(sp)
400d74: afbe0018 sw s8,24(sp)
400d78: 03a0f021 move s8,sp
400d7c: afc40020 sw a0,32(s8) //将$a0的内容存入栈
400d80: 8fc40020 lw a0,32(s8)
400d84: 3c020040 lui v0,0x40
400d88: 2445276c addiu a1,v0,10092 //加载参数到$a1
400d8c: 0c10073e jal 401cf8 <strings_not_equal> //比较字符串$a0和$a1,不相等则$v0 = 1,否则$v0 = 1
400d90: 00000000 nop
400d94: 10400003 beqz v0,400da4 <phase_1+0x38> //若$v0 == 0则跳至0x00400da4处
400d98: 00000000 nop
400d9c: 0c10087c jal 4021f0 <explode_bomb> //否则若$v0 == 0则爆炸
400da0: 00000000 nop
400da4: 03c0e821 move sp,s8
400da8: 8fbf001c lw ra,28(sp)
400dac: 8fbe0018 lw s8,24(sp)
400db0: 27bd0020 addiu sp,sp,32
400db4: 03e00008 jr ra
400db8: 00000000 nop
phase_2
该炸弹要求我们输入六个数字(看函数名称识功能,第1个数必须为1),之后进入循环中一个个对这些数字进行处理,将第i个数分别与学号倒数i位相乘结果与第i+1个数比较判断是否相等,意味着我们输入的六个数就是对ID后五位累乘的序列。为什么知道是ID后五位?读寄存器得到的。ID不够五位?那就相当于定义了一个变量却没有赋值,一样能解决这个炸弹。这个炸弹不理解代码强行在0x400e80处读$a0的值并反复尝试令其与$v0相等也能解决,当然不推荐就是了。
00400dbc <phase_2>:
400dbc: 27bdffc0 addiu sp,sp,-64
400dc0: afbf003c sw ra,60(sp)
400dc4: afbe0038 sw s8,56(sp)
400dc8: 03a0f021 move s8,sp
400dcc: 3c1c0042 lui gp,0x42
400dd0: 279cb190 addiu gp,gp,-20080
400dd4: afbc0010 sw gp,16(sp)
400dd8: afc40040 sw a0,64(s8)
400ddc: 27c2001c addiu v0,s8,28
400de0: 8fc40040 lw a0,64(s8)
400de4: 00402821 move a1,v0
400de8: 0c1006ea jal 401ba8 <read_six_numbers> //读入6个数字
400dec: 00000000 nop
400df0: 8fdc0010 lw gp,16(s8)
400df4: 8fc3001c lw v1,28(s8) //m[$s8+28]存有读入的第一个数,将其存入$v1
400df8: 24020001 li v0,1
400dfc: 10620004 beq v1,v0,400e10 <phase_2+0x54> //判定$v1是否为1,不是则引爆
400e00: 00000000 nop
400e04: 0c10087c jal 4021f0 <explode_bomb>
400e08: 00000000 nop
400e0c: 8fdc0010 lw gp,16(s8)
400e10: 24020001 li v0,1 //设定循环单次表达式$v0 = 1(i = 1)
400e14: afc20018 sw v0,24(s8) //将$v0(i)存入栈
400e18: 10000023 b 400ea8 <phase_2+0xec> //循环开始,跳至条件表达式
400e1c: 00000000 nop
400e20: 8fc20018 lw v0,24(s8) //将之前存在栈中的变量i取出
400e24: 00000000 nop
400e28: 2442ffff addiu v0,v0,-1 //$v0自减
400e2c: 00021080 sll v0,v0,0x2 //$v0 = $v0 * 4(拓到1 int长度)
400e30: 27c30018 addiu v1,s8,24 //第i个数的存放位置为m[$s8 + 24 + i * 4](一个int型变量占4个字节)
400e34: 00621021 addu v0,v1,v0
400e38: 8c440004 lw a0,4(v0) //将第i个数的值存入$a0(所以前面自减有意义吗)
400e3c: 2403000c li v1,12
400e40: 8fc20018 lw v0,24(s8) //将之前存在栈中的变量i取出
400e44: 00000000 nop
400e48: 00621023 subu v0,v1,v0 //$v0 = $v1(12) - $v0(i)
400e4c: 8f83806c lw v1,-32660(gp) //读得输入的学号
400e50: 00021080 sll v0,v0,0x2 //$v0 = $v0 * 4(拓到1 int长度)
400e54: 00621021 addu v0,v1,v0 //$v0 = $v1 + $v0
400e58: 8c420000 lw v0,0(v0) //将学号的倒数i位读入$v0中
400e5c: 00000000 nop
400e60: 00820018 mult a0,v0 //$a0与$v0相乘
400e64: 00002012 mflo a0 //将结果存入$a0
400e68: 8fc20018 lw v0,24(s8) //将之前存在栈中的变量i取出
400e6c: 00000000 nop
400e70: 00021080 sll v0,v0,0x2 //$v0 = $v0 * 4(拓到1 int长度)
400e74: 27c30018 addiu v1,s8,24 //第i个数得存放位置为m[$s8 + 24 + i * 4](一个int型变量占4个字节)
400e78: 00621021 addu v0,v1,v0 //得到第i个数的位置
400e7c: 8c420004 lw v0,4(v0) //将第i + 1个数的值存入$v0
400e80: 00000000 nop
400e84: 10820004 beq a0,v0,400e98 <phase_2+0xdc> //比较$a0(第i个数与学号的倒数i位相乘的结果)与$v0(第i + 1个数),若不相等则引爆
400e88: 00000000 nop
400e8c: 0c10087c jal 4021f0 <explode_bomb>
400e90: 00000000 nop
400e94: 8fdc0010 lw gp,16(s8) //末尾循环体
400e98: 8fc20018 lw v0,24(s8)
400e9c: 00000000 nop
400ea0: 24420001 addiu v0,v0,1 //i自加
400ea4: afc20018 sw v0,24(s8) //将i存入栈中
400ea8: 8fc20018 lw v0,24(s8)
400eac: 00000000 nop
400eb0: 28420006 slti v0,v0,6 //判断循环是否结束,相当于i != 6(i < 6)
400eb4: 1440ffda bnez v0,400e20 <phase_2+0x64>
400eb8: 00000000 nop
400ebc: 03c0e821 move sp,s8
400ec0: 8fbf003c lw ra,60(sp)
400ec4: 8fbe0038 lw s8,56(sp)
400ec8: 27bd0040 addiu sp,sp,64
400ecc: 03e00008 jr ra
400ed0: 00000000 nop
phase_3
考察分支结构(switch…case…结构)。要求输入格式为"%d %c %d"(看调用数据时的指令得到的,word/byte的区别),第一个数就是switch语句中的变量,跳至不同的case语句(0到7共八个,超出直接引爆)。除case 3外,其他数均是要求一个数与输入的第三个数相乘的结果为指定的立即数,而case 3要求相乘结果为0。读寄存器可知该数为输入ID的最后一位。另外在每个case结构的开头都将一个字符存入栈中,在switch…case…结束后与我们输入的字符比较,令两个字符相等即可。
00400ed4 <phase_3>:
400ed4: 27bdffc8 addiu sp,sp,-56
400ed8: afbf0034 sw ra,52(sp)
400edc: afbe0030 sw s8,48(sp)
400ee0: 03a0f021 move s8,sp
400ee4: 3c1c0042 lui gp,0x42
400ee8: 279cb190 addiu gp,gp,-20080
400eec: afbc0018 sw gp,24(sp)
400ef0: afc40038 sw a0,56(s8)
400ef4: 8fc40038 lw a0,56(s8)
400ef8: 3c020040 lui v0,0x40
400efc: 24452780 addiu a1,v0,10112
400f00: 27c3002c addiu v1,s8,44
400f04: 27c20028 addiu v0,s8,40
400f08: 27c60024 addiu a2,s8,36
400f0c: afa60010 sw a2,16(sp)
400f10: 00603021 move a2,v1
400f14: 00403821 move a3,v0
400f18: 8f828084 lw v0,-32636(gp)
400f1c: 00000000 nop
400f20: 0040c821 move t9,v0
400f24: 0320f809 jalr t9
400f28: 00000000 nop
400f2c: 8fdc0018 lw gp,24(s8)
400f30: 28420003 slti v0,v0,3 //判定输入的数据个数是否为3
400f34: 10400004 beqz v0,400f48 <phase_3+0x74>
400f38: 00000000 nop
400f3c: 0c10087c jal 4021f0 <explode_bomb>
400f40: 00000000 nop
400f44: 8fdc0018 lw gp,24(s8)
400f48: 8fc2002c lw v0,44(s8) //读入输入的第一个数至$v0
400f4c: 00000000 nop
400f50: 2c430008 sltiu v1,v0,8 //判断$v0是否小于8,是则继续,否则引爆
400f54: 1060008e beqz v1,401190 <phase_3+0x2bc>
400f58: 00000000 nop
400f5c: 00021880 sll v1,v0,0x2 //$v1 = $v0 * 4,拓至1 int型变量长度
400f60: 3c020040 lui v0,0x40
400f64: 2442278c addiu v0,v0,10124
400f68: 00621021 addu v0,v1,v0
400f6c: 8c420000 lw v0,0(v0) //$v0对应case语句的地址,用x $v0查看
400f70: 00000000 nop
400f74: 00400008 jr v0 //switch语句,跳至相应的case语句
400f78: 00000000 nop //case 0:
400f7c: 24020071 li v0,113 //q的ASCII码
400f80: a3c20020 sb v0,32(s8) //存入1byte的数据
400f84: 8f82806c lw v0,-32660(gp)
400f88: 00000000 nop
400f8c: 8c43002c lw v1,44(v0) //读入学号的最后一位
400f90: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
400f94: 00000000 nop
400f98: 00620018 mult v1,v0
400f9c: 00001812 mflo v1 //$v1 = $v1 * $v0
400fa0: 24020309 li v0,777 //判断是否为777(=3*=7*111),是则break,否则引爆
400fa4: 10620081 beq v1,v0,4011ac <phase_3+0x2d8>
400fa8: 00000000 nop
400fac: 0c10087c jal 4021f0 <explode_bomb>
400fb0: 00000000 nop
400fb4: 8fdc0018 lw gp,24(s8)
400fb8: 1000008f b 4011f8 <phase_3+0x324>
400fbc: 00000000 nop //case 1:
400fc0: 24020062 li v0,98 //b的ASCII码
400fc4: a3c20020 sb v0,32(s8) //存入1byte的数据
400fc8: 8f82806c lw v0,-32660(gp)
400fcc: 00000000 nop
400fd0: 8c43002c lw v1,44(v0) //读入学号的最后一位
400fd4: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
400fd8: 00000000 nop
400fdc: 00620018 mult v1,v0
400fe0: 00001812 mflo v1 //$v1 = $v1 * $v0
400fe4: 240200d6 li v0,214 //判断是否为214(=2*107),是则break,否则引爆
400fe8: 10620073 beq v1,v0,4011b8 <phase_3+0x2e4>
400fec: 00000000 nop
400ff0: 0c10087c jal 4021f0 <explode_bomb>
400ff4: 00000000 nop
400ff8: 8fdc0018 lw gp,24(s8)
400ffc: 1000007e b 4011f8 <phase_3+0x324>
401000: 00000000 nop //case 2:
401004: 24020062 li v0,98 //b的ASCII码
401008: a3c20020 sb v0,32(s8) //存入1byte的数据
40100c: 8f82806c lw v0,-32660(gp)
401010: 00000000 nop
401014: 8c43002c lw v1,44(v0) //读入学号的最后一位
401018: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
40101c: 00000000 nop
401020: 00620018 mult v1,v0
401024: 00001812 mflo v1 //$v1 = $v1 * $v0
401028: 240202f3 li v0,755 //判断是否为755(=5*151),是则break,否则引爆
40102c: 10620065 beq v1,v0,4011c4 <phase_3+0x2f0>
401030: 00000000 nop
401034: 0c10087c jal 4021f0 <explode_bomb>
401038: 00000000 nop
40103c: 8fdc0018 lw gp,24(s8)
401040: 1000006d b 4011f8 <phase_3+0x324>
401044: 00000000 nop //case 3:
401048: 2402006b li v0,107 //k的ASCII码
40104c: a3c20020 sb v0,32(s8) //存入1byte的数据
401050: 8f82806c lw v0,-32660(gp)
401054: 00000000 nop
401058: 8c43002c lw v1,44(v0) //读入学号的最后一位
40105c: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
401060: 00000000 nop
401064: 00620018 mult v1,v0
401068: 00001012 mflo v0 //$v0 = $v1 * $v0
40106c: 10400058 beqz v0,4011d0 <phase_3+0x2fc> //判断$v0是否等于0,是则break,否则引爆
401070: 00000000 nop
401074: 0c10087c jal 4021f0 <explode_bomb>
401078: 00000000 nop
40107c: 8fdc0018 lw gp,24(s8)
401080: 1000005d b 4011f8 <phase_3+0x324>
401084: 00000000 nop //case 4:
401088: 2402006f li v0,111 //o的ASCII码
40108c: a3c20020 sb v0,32(s8) //存入1byte的数据
401090: 8f82806c lw v0,-32660(gp)
401094: 00000000 nop
401098: 8c43002c lw v1,44(v0) //读入学号的最后一位
40109c: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
4010a0: 00000000 nop
4010a4: 00620018 mult v1,v0
4010a8: 00001812 mflo v1 //$v1 = $v1 * $v0
4010ac: 240200e4 li v0,228 //判断是否为228(=2*114=4*57),是则break,否则引爆 ???
4010b0: 1062004a beq v1,v0,4011dc <phase_3+0x308>
4010b4: 00000000 nop
4010b8: 0c10087c jal 4021f0 <explode_bomb>
4010bc: 00000000 nop
4010c0: 8fdc0018 lw gp,24(s8)
4010c4: 1000004c b 4011f8 <phase_3+0x324>
4010c8: 00000000 nop //case 5:
4010cc: 24020074 li v0,116 //t的ASCII码
4010d0: a3c20020 sb v0,32(s8) //存入1byte的数据
4010d4: 8f82806c lw v0,-32660(gp)
4010d8: 00000000 nop
4010dc: 8c43002c lw v1,44(v0) //读入学号的最后一位
4010e0: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
4010e4: 00000000 nop
4010e8: 00620018 mult v1,v0
4010ec: 00001812 mflo v1 //$v1 = $v1 * $v0
4010f0: 24020201 li v0,513 //判断是否为513(=3*171=9*57),是则break,否则引爆
4010f4: 1062003c beq v1,v0,4011e8 <phase_3+0x314>
4010f8: 00000000 nop
4010fc: 0c10087c jal 4021f0 <explode_bomb>
401100: 00000000 nop
401104: 8fdc0018 lw gp,24(s8)
401108: 1000003b b 4011f8 <phase_3+0x324>
40110c: 00000000 nop //case 6:
401110: 24020076 li v0,118 //v的ASCII码
401114: a3c20020 sb v0,32(s8) //存入1byte的数据
401118: 8f82806c lw v0,-32660(gp)
40111c: 00000000 nop
401120: 8c43002c lw v1,44(v0) //读入学号的最后一位
401124: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
401128: 00000000 nop
40112c: 00620018 mult v1,v0
401130: 00001812 mflo v1 //$v1 = $v1 * $v0
401134: 2402030c li v0,780 //判断是否为780(=2*390=3*260=4*195=5*156=6*130),是则break,否则引爆
401138: 10620004 beq v1,v0,40114c <phase_3+0x278>
40113c: 00000000 nop
401140: 0c10087c jal 4021f0 <explode_bomb>
401144: 00000000 nop //case 7:
401148: 8fdc0018 lw gp,24(s8) ???
40114c: 24020062 li v0,98 //b的ASCII码
401150: a3c20020 sb v0,32(s8) //存入1byte的数据
401154: 8f82806c lw v0,-32660(gp)
401158: 00000000 nop
40115c: 8c43002c lw v1,44(v0) //读入学号的最后一位
401160: 8fc20024 lw v0,36(s8) //读入输入数据的第三个数
401164: 00000000 nop
401168: 00620018 mult v1,v0
40116c: 00001812 mflo v1 //$v1 = $v1 * $v0
401170: 24020338 li v0,824 //判断是否为824(=2*412=4*206),是则break,否则引爆
401174: 1062001f beq v1,v0,4011f4 <phase_3+0x320>
401178: 00000000 nop
40117c: 0c10087c jal 4021f0 <explode_bomb>
401180: 00000000 nop
401184: 8fdc0018 lw gp,24(s8)
401188: 1000001b b 4011f8 <phase_3+0x324>
40118c: 00000000 nop
401190: 24020078 li v0,120
401194: a3c20020 sb v0,32(s8)
401198: 0c10087c jal 4021f0 <explode_bomb>
40119c: 00000000 nop
4011a0: 8fdc0018 lw gp,24(s8)
4011a4: 10000014 b 4011f8 <phase_3+0x324>
4011a8: 00000000 nop
4011ac: 00000000 nop
4011b0: 10000011 b 4011f8 <phase_3+0x324>
4011b4: 00000000 nop
4011b8: 00000000 nop
4011bc: 1000000e b 4011f8 <phase_3+0x324>
4011c0: 00000000 nop
4011c4: 00000000 nop
4011c8: 1000000b b 4011f8 <phase_3+0x324>
4011cc: 00000000 nop
4011d0: 00000000 nop
4011d4: 10000008 b 4011f8 <phase_3+0x324>
4011d8: 00000000 nop
4011dc: 00000000 nop
4011e0: 10000005 b 4011f8 <phase_3+0x324>
4011e4: 00000000 nop
4011e8: 00000000 nop
4011ec: 10000002 b 4011f8 <phase_3+0x324>
4011f0: 00000000 nop
4011f4: 00000000 nop
4011f8: 83c20028 lb v0,40(s8) //输入的第二个字符数据
4011fc: 83c30020 lb v1,32(s8) //将case语句中存的字符取出
401200: 00000000 nop
401204: 10620004 beq v1,v0,401218 <phase_3+0x344> //比较,不相等则引爆
401208: 00000000 nop
40120c: 0c10087c jal 4021f0 <explode_bomb>
401210: 00000000 nop
401214: 8fdc0018 lw gp,24(s8)
401218: 03c0e821 move sp,s8
40121c: 8fbf0034 lw ra,52(sp)
401220: 8fbe0030 lw s8,48(sp)
401224: 27bd0038 addiu sp,sp,56
401228: 03e00008 jr ra
40122c: 00000000 nop
phase_4
该炸弹使用了if…else…语句和递归结构,学号最后一位的奇偶分别进入判断fun4(x)是否与8和13相等,很容易联想到斐波那契数列。而调用的fun4也是计算f(x)=f(x-1)+f(x-2),正是斐波那契数列的递归解法。那么输入的数字x就是函数fun4的参数。注意fun4定义f(0)=f(1)=1,与通常的斐波那契数列不同,所以答案为5或6。
00401230 <func4>:
401230: 27bdffd8 addiu sp,sp,-40
401234: afbf0024 sw ra,36(sp)
401238: afbe0020 sw s8,32(sp)
40123c: afb0001c sw s0,28(sp)
401240: 03a0f021 move s8,sp
401244: afc40028 sw a0,40(s8)
401248: 8fc20028 lw v0,40(s8)
40124c: 00000000 nop
401250: 28420002 slti v0,v0,2 //判断$v0是否小于2,是则$v0 = 1
401254: 14400011 bnez v0,40129c <func4+0x6c> //$v0 != 0则return 1
401258: 00000000 nop
40125c: 8fc20028 lw v0,40(s8)
401260: 00000000 nop
401264: 2442ffff addiu v0,v0,-1
401268: 00402021 move a0,v0
40126c: 0c10048c jal 401230 <func4> //递归引用自身f(x - 1)
401270: 00000000 nop
401274: 00408021 move s0,v0 //将f(x - 1)的结果存入$s0
401278: 8fc20028 lw v0,40(s8)
40127c: 00000000 nop
401280: 2442fffe addiu v0,v0,-2
401284: 00402021 move a0,v0
401288: 0c10048c jal 401230 <func4> //递归引用自身f(x - 2)
40128c: 00000000 nop
401290: 02021021 addu v0,s0,v0 //$v0 = f(x - 1) + f(x - 2),返回$v0
401294: 10000002 b 4012a0 <func4+0x70>
401298: 00000000 nop
40129c: 24020001 li v0,1 //return 1
4012a0: 03c0e821 move sp,s8
4012a4: 8fbf0024 lw ra,36(sp)
4012a8: 8fbe0020 lw s8,32(sp)
4012ac: 8fb0001c lw s0,28(sp)
4012b0: 27bd0028 addiu sp,sp,40
4012b4: 03e00008 jr ra
4012b8: 00000000 nop
004012bc <phase_4>:
4012bc: 27bdffd8 addiu sp,sp,-40
4012c0: afbf0024 sw ra,36(sp)
4012c4: afbe0020 sw s8,32(sp)
4012c8: 03a0f021 move s8,sp
4012cc: 3c1c0042 lui gp,0x42
4012d0: 279cb190 addiu gp,gp,-20080
4012d4: afbc0010 sw gp,16(sp)
4012d8: afc40028 sw a0,40(s8)
4012dc: 8fc30028 lw v1,40(s8)
4012e0: 3c020040 lui v0,0x40
4012e4: 244227ac addiu v0,v0,10156
4012e8: 00602021 move a0,v1
4012ec: 00402821 move a1,v0
4012f0: 27c20018 addiu v0,s8,24
4012f4: 00403021 move a2,v0
4012f8: 8f828084 lw v0,-32636(gp)
4012fc: 00000000 nop
401300: 0040c821 move t9,v0
401304: 0320f809 jalr t9
401308: 00000000 nop
40130c: 8fdc0010 lw gp,16(s8)
401310: 00401821 move v1,v0
401314: 24020001 li v0,1
401318: 14620005 bne v1,v0,401330 <phase_4+0x74> //$v0 != 1则引爆
40131c: 00000000 nop
401320: 8fc20018 lw v0,24(s8)
401324: 00000000 nop
401328: 1c400005 bgtz v0,401340 <phase_4+0x84>
40132c: 00000000 nop
401330: 0c10087c jal 4021f0 <explode_bomb>
401334: 00000000 nop
401338: 8fdc0010 lw gp,16(s8)
40133c: 00000000 nop
401340: 8f82806c lw v0,-32660(gp)
401344: 00000000 nop
401348: 8c42002c lw v0,44(v0) //令$v0等于学号的最后一位
40134c: 00000000 nop
401350: 30420001 andi v0,v0,0x1 //判定奇偶
401354: 304200ff andi v0,v0,0xff
401358: 10400010 beqz v0,40139c <phase_4+0xe0> //if...else...结构,奇数(1)继续,偶数(0)跳转
40135c: 00000000 nop
401360: 8fc20018 lw v0,24(s8) //令$v0等于输入的第一个数
401364: 00000000 nop
401368: 00402021 move a0,v0 //传入参数
40136c: 0c10048c jal 401230 <func4> //计算f(x)
401370: 00000000 nop
401374: 8fdc0010 lw gp,16(s8)
401378: 00401821 move v1,v0
40137c: 24020008 li v0,8
401380: 10620013 beq v1,v0,4013d0 <phase_4+0x114> //f(x) = $v1 != 8则引爆,则x = 5
401384: 00000000 nop
401388: 0c10087c jal 4021f0 <explode_bomb>
40138c: 00000000 nop
401390: 8fdc0010 lw gp,16(s8)
401394: 1000000e b 4013d0 <phase_4+0x114>
401398: 00000000 nop
40139c: 8fc20018 lw v0,24(s8)
4013a0: 00000000 nop
4013a4: 00402021 move a0,v0 //传入参数
4013a8: 0c10048c jal 401230 <func4> //计算f(x)
4013ac: 00000000 nop
4013b0: 8fdc0010 lw gp,16(s8)
4013b4: 00401821 move v1,v0
4013b8: 2402000d li v0,13
4013bc: 10620004 beq v1,v0,4013d0 <phase_4+0x114> //f(x) = $v1 != 13则引爆,则x = 6
4013c0: 00000000 nop
4013c4: 0c10087c jal 4021f0 <explode_bomb>
4013c8: 00000000 nop
4013cc: 8fdc0010 lw gp,16(s8)
4013d0: 03c0e821 move sp,s8
4013d4: 8fbf0024 lw ra,36(sp)
4013d8: 8fbe0020 lw s8,32(sp)
4013dc: 27bd0028 addiu sp,sp,40
4013e0: 03e00008 jr ra
4013e4: 00000000 nop
phase_5
输入字符串,要求其长度为6。进入循环中对每个字符进行处理,获取其二进制数的后四位(即ASCII码的b3b2b1b0),一一对应程序存储的长度为16的字符串S=“isrveawhobpnutfg”,即S[b3b2b1b0],炸弹要求这个映射获得的字符串为"giants",那么输入的字符串就可以是opekma,应当也可以是其他可以映射的字符串(大概没有限制?上机验证一下就知道了)
004013e8 <phase_5>:
4013e8: 27bdffb8 addiu sp,sp,-72
4013ec: afbf0044 sw ra,68(sp)
4013f0: afbe0040 sw s8,64(sp)
4013f4: 03a0f021 move s8,sp
4013f8: afc40048 sw a0,72(s8) //$a0为输入的字符串,将其存入栈中
4013fc: 8fc40048 lw a0,72(s8)
401400: 0c10071e jal 401c78 <string_length>
401404: 00000000 nop
401408: 00401821 move v1,v0
40140c: 24020006 li v0,6
401410: 10620003 beq v1,v0,401420 <phase_5+0x38> //输入字符串长度$v1 != 6则引爆
401414: 00000000 nop
401418: 0c10087c jal 4021f0 <explode_bomb>
40141c: 00000000 nop
401420: afc00018 sw zero,24(s8) //i = 0
401424: 10000020 b 4014a8 <phase_5+0xc0>
401428: 00000000 nop
40142c: 8fc20018 lw v0,24(s8) //读得i
401430: 8fc30018 lw v1,24(s8) //读得i
401434: 8fc40048 lw a0,72(s8) //从栈中取出输入的字符串(从0开始编号)
401438: 00000000 nop
40143c: 00831821 addu v1,a0,v1
401440: 80630000 lb v1,0(v1) //读取输入字符串的第i个字符
401444: 00000000 nop
401448: 306300ff andi v1,v1,0xff
40144c: 3063000f andi v1,v1,0xf //取字符转化为二进制数(1byte=8bit)的后四位
401450: 00021080 sll v0,v0,0x2 //将i拓至1 int型变量长度
401454: 27c40018 addiu a0,s8,24 //读得i的地址
401458: 00821021 addu v0,a0,v0
40145c: ac43000c sw v1,12(v0) //将字符后四位存入m[$s8 + 36 + i * 4]
401460: 8fc40018 lw a0,24(s8) //读得i
401464: 8fc20018 lw v0,24(s8) //读得i
401468: 00000000 nop
40146c: 00021080 sll v0,v0,0x2 //将i拓至1 int型变量长度
401470: 27c30018 addiu v1,s8,24 //读得i的地址
401474: 00621021 addu v0,v1,v0
401478: 8c43000c lw v1,12(v0) //读得字符后四位,存入$v1中
40147c: 3c020041 lui v0,0x41
401480: 244230ec addiu v0,v0,12524 //获取存储的字符串S(从0开始编号)的位置 $v0 = isrveawhobpnutfg
401484: 00621021 addu v0,v1,v0 //得到第$v1个字符的内存地址
401488: 80430000 lb v1,0(v0) //得到第$v1(输入字符串的第i个字符的后四位,即ASCII码的b3b2b1b0)个字符
40148c: 27c20018 addiu v0,s8,24
401490: 00441021 addu v0,v0,a0
401494: a0430004 sb v1,4(v0) //将获得的字符存入m[$s8 + 28 + i]
401498: 8fc20018 lw v0,24(s8) //读得i
40149c: 00000000 nop
4014a0: 24420001 addiu v0,v0,1 //i++
4014a4: afc20018 sw v0,24(s8)
4014a8: 8fc20018 lw v0,24(s8)
4014ac: 00000000 nop
4014b0: 28420006 slti v0,v0,6 //$v0 = ($v0 < 6 ? 1 : 0),为1再循环一次,即i < 6
4014b4: 1440ffdd bnez v0,40142c <phase_5+0x44>
4014b8: 00000000 nop
4014bc: a3c00022 sb zero,34(s8) //将字符串尾设为'\0'
4014c0: 27c2001c addiu v0,s8,28
4014c4: 00402021 move a0,v0 //从内存中获取依靠映射从存储的字符串S中得到的字符串
4014c8: 3c020040 lui v0,0x40
4014cc: 244527b0 addiu a1,v0,10160 //从内存中获取用来比较的字符串
4014d0: 0c10073e jal 401cf8 <strings_not_equal> //比较$a0,$a1
4014d4: 00000000 nop
4014d8: 10400003 beqz v0,4014e8 <phase_5+0x100>
4014dc: 00000000 nop
4014e0: 0c10087c jal 4021f0 <explode_bomb>
4014e4: 00000000 nop
4014e8: 03c0e821 move sp,s8
4014ec: 8fbf0044 lw ra,68(sp)
4014f0: 8fbe0040 lw s8,64(sp)
4014f4: 27bd0048 addiu sp,sp,72
4014f8: 03e00008 jr ra
4014fc: 00000000 nop
phase_6
b* 0x4016e0
r
//node[] = {0fd, 2d5, 12d, 3e5, 0d4, 1b0}
x $v1 //node[i]
c
x $v1
c
x $v1
c
x $v1
c
x $v1
c
x $v1
c
00401500 <phase_6>:
401500: 27bdffa0 addiu sp,sp,-96
401504: afbf005c sw ra,92(sp)
401508: afbe0058 sw s8,88(sp)
40150c: 03a0f021 move s8,sp
401510: 3c1c0042 lui gp,0x42
401514: 279cb190 addiu gp,gp,-20080
401518: afbc0010 sw gp,16(sp)
40151c: afc40060 sw a0,96(s8)
401520: 3c020041 lui v0,0x41
401524: 24423130 addiu v0,v0,12592
401528: afc20020 sw v0,32(s8)
40152c: 27c20024 addiu v0,s8,36
401530: 8fc40060 lw a0,96(s8)
401534: 00402821 move a1,v0
401538: 0c1006ea jal 401ba8 <read_six_numbers> # 输入六个数字
40153c: 00000000 nop # 第一层循环的初始条件设定
401540: 8fdc0010 lw gp,16(s8)
401544: afc0001c sw zero,28(s8) # i = 0
401548: 1000003c b 40163c <phase_6+0x13c> # 跳至0x40163c处条件判断处
40154c: 00000000 nop # 第一层循环中间循环体开始
401550: 8fc2001c lw v0,28(s8) # 获取i
401554: 00000000 nop
401558: 00021080 sll v0,v0,0x2 #拓至1int长度
40155c: 27c30018 addiu v1,s8,24
401560: 00621021 addu v0,v1,v0
401564: 8c42000c lw v0,12(v0) # 得到输入的第i个数
401568: 00000000 nop
40156c: 28420007 slti v0,v0,7 # 判断第i个数是否小于7
401570: 1040000a beqz v0,40159c <phase_6+0x9c> # 否则引爆
401574: 00000000 nop
401578: 8fc2001c lw v0,28(s8)
40157c: 00000000 nop
401580: 00021080 sll v0,v0,0x2
401584: 27c30018 addiu v1,s8,24
401588: 00621021 addu v0,v1,v0
40158c: 8c42000c lw v0,12(v0)
401590: 00000000 nop
401594: 1c400004 bgtz v0,4015a8 <phase_6+0xa8> # 判断第i个数是否大于0,否则引爆
401598: 00000000 nop
40159c: 0c10087c jal 4021f0 <explode_bomb>
4015a0: 00000000 nop
4015a4: 8fdc0010 lw gp,16(s8)
4015a8: 8fc2001c lw v0,28(s8)
4015ac: 00000000 nop # 第二层循环的初始条件设定
4015b0: 24420001 addiu v0,v0,1 # j = i + 1
4015b4: afc20018 sw v0,24(s8) # 将j存至m[$s8 + 24]处
4015b8: 10000017 b 401618 <phase_6+0x118> # 跳至0x401618条件判断处
4015bc: 00000000 nop # 第二层循环中间循环体开始
4015c0: 8fc2001c lw v0,28(s8) # 获取i
4015c4: 00000000 nop
4015c8: 00021080 sll v0,v0,0x2
4015cc: 27c30018 addiu v1,s8,24
4015d0: 00621021 addu v0,v1,v0
4015d4: 8c43000c lw v1,12(v0) # 获取第i个数
4015d8: 8fc20018 lw v0,24(s8) # 获取j
4015dc: 00000000 nop
4015e0: 00021080 sll v0,v0,0x2
4015e4: 27c40018 addiu a0,s8,24
4015e8: 00821021 addu v0,a0,v0
4015ec: 8c42000c lw v0,12(v0) # 获取第j个数
4015f0: 00000000 nop
4015f4: 14620004 bne v1,v0,401608 <phase_6+0x108> #判断第i个数和第j个数是否不相等,否则爆炸
4015f8: 00000000 nop
4015fc: 0c10087c jal 4021f0 <explode_bomb>
401600: 00000000 nop
401604: 8fdc0010 lw gp,16(s8)
401608: 8fc20018 lw v0,24(s8)
40160c: 00000000 nop # 第二层循环末尾循环体
401610: 24420001 addiu v0,v0,1 # j++
401614: afc20018 sw v0,24(s8)
401618: 8fc20018 lw v0,24(s8) # 第二层循环条件判断处
40161c: 00000000 nop
401620: 28420006 slti v0,v0,6 # 当j < 6时,继续循环
401624: 1440ffe6 bnez v0,4015c0 <phase_6+0xc0>
401628: 00000000 nop
40162c: 8fc2001c lw v0,28(s8) # 获取i
401630: 00000000 nop # 第一层循环末尾循环体
401634: 24420001 addiu v0,v0,1 # i++
401638: afc2001c sw v0,28(s8)
40163c: 8fc2001c lw v0,28(s8) # 第一层循环条件判断处
401640: 00000000 nop
401644: 28420006 slti v0,v0,6 # 当i < 6 时,继续循环
401648: 1440ffc1 bnez v0,401550 <phase_6+0x50>
40164c: 00000000 nop # 第一层循环的初始条件
401650: afc0001c sw zero,28(s8) # i = 0
401654: 10000028 b 4016f8 <phase_6+0x1f8> # 跳至条件判断处
401658: 00000000 nop # 第二层循环的初始条件
40165c: 3c020041 lui v0,0x41
401660: 24423130 addiu v0,v0,12592 # 令$v0等于&firstnode = 0x413130
401664: afc20020 sw v0,32(s8) # m[$s8 + 32] = &firstnode
401668: 24020001 li v0,1 # j = 1
40166c: afc20018 sw v0,24(s8)
401670: 1000000a b 40169c <phase_6+0x19c> # 跳至条件判断处
401674: 00000000 nop
401678: 8fc20020 lw v0,32(s8) # 取得&node
40167c: 00000000 nop
401680: 8c420008 lw v0,8(v0) # $v0 = m[$v0 + 8]
401684: 00000000 nop
401688: afc20020 sw v0,32(s8) # node = node->next
40168c: 8fc20018 lw v0,24(s8) # 取得j
401690: 00000000 nop
401694: 24420001 addiu v0,v0,1 # j++
401698: afc20018 sw v0,24(s8)
40169c: 8fc2001c lw v0,28(s8) # 取得i
4016a0: 00000000 nop
4016a4: 00021080 sll v0,v0,0x2
4016a8: 27c30018 addiu v1,s8,24
4016ac: 00621021 addu v0,v1,v0
4016b0: 8c43000c lw v1,12(v0) # 取得输入的第i个数
4016b4: 8fc20018 lw v0,24(s8)
4016b8: 00000000 nop
4016bc: 0043102a slt v0,v0,v1 # 判断j是否小于输入的第i个数,是则循环继续
4016c0: 1440ffed bnez v0,401678 <phase_6+0x178>
4016c4: 00000000 nop
4016c8: 8fc2001c lw v0,28(s8) # 取得i
4016cc: 00000000 nop
4016d0: 00021080 sll v0,v0,0x2
4016d4: 27c30018 addiu v1,s8,24
4016d8: 00621021 addu v0,v1,v0
4016dc: 8fc30020 lw v1,32(s8) # 将node = [链表的第j/【输入的第i个数】个取出
4016e0: 00000000 nop
4016e4: ac430024 sw v1,36(v0) # 存入数组res的res[i]中
4016e8: 8fc2001c lw v0,28(s8)
4016ec: 00000000 nop
4016f0: 24420001 addiu v0,v0,1
4016f4: afc2001c sw v0,28(s8)
4016f8: 8fc2001c lw v0,28(s8) # 条件判断处
4016fc: 00000000 nop
401700: 28420006 slti v0,v0,6 # i < 6 则循环继续
401704: 1440ffd5 bnez v0,40165c <phase_6+0x15c>
401708: 00000000 nop
40170c: 8fc2003c lw v0,60(s8)
401710: 00000000 nop
401714: afc20020 sw v0,32(s8) # node = firstnode ???
401718: 24020001 li v0,1
40171c: afc2001c sw v0,28(s8) # i = 1
401720: 10000016 b 40177c <phase_6+0x27c>
401724: 00000000 nop # 循环开始
401728: 8fc2001c lw v0,28(s8) # 取得i
40172c: 00000000 nop
401730: 00021080 sll v0,v0,0x2
401734: 27c30018 addiu v1,s8,24
401738: 00621021 addu v0,v1,v0
40173c: 8c430024 lw v1,36(v0) # 取得res[i]
401740: 8fc20020 lw v0,32(s8) # 取得node
401744: 00000000 nop
401748: ac430008 sw v1,8(v0) # node->next = res[i]
40174c: 8fc2001c lw v0,28(s8) # 取得i
401750: 00000000 nop
401754: 00021080 sll v0,v0,0x2
401758: 27c30018 addiu v1,s8,24
40175c: 00621021 addu v0,v1,v0
401760: 8c420024 lw v0,36(v0) # 取得res[i]
401764: 00000000 nop
401768: afc20020 sw v0,32(s8) # node = res[i]
40176c: 8fc2001c lw v0,28(s8) # 末尾循环体起始,取得i
401770: 00000000 nop
401774: 24420001 addiu v0,v0,1 # i++
401778: afc2001c sw v0,28(s8) # 存入内存中
40177c: 8fc2001c lw v0,28(s8) # 条件判断起始
401780: 00000000 nop
401784: 28420006 slti v0,v0,6 # 判断i < 6,是则循环继续
401788: 1440ffe7 bnez v0,401728 <phase_6+0x228>
40178c: 00000000 nop
401790: 8fc20020 lw v0,32(s8)
401794: 00000000 nop
401798: ac400008 sw zero,8(v0) # node->next = null
40179c: 8fc2003c lw v0,60(s8)
4017a0: 00000000 nop
4017a4: afc20020 sw v0,32(s8) # node = firstnode
4017a8: afc0001c sw zero,28(s8) # i = 0
4017ac: 10000032 b 401878 <phase_6+0x378>
4017b0: 00000000 nop
4017b4: 8f82806c lw v0,-32660(gp)
4017b8: 00000000 nop
4017bc: 8c42002c lw v0,44(v0)
4017c0: 00000000 nop
4017c4: 30420001 andi v0,v0,0x1
4017c8: 304200ff andi v0,v0,0xff
4017cc: 10400012 beqz v0,401818 <phase_6+0x318> # if...else语句,判断奇偶
4017d0: 00000000 nop
4017d4: 8fc20020 lw v0,32(s8)
4017d8: 00000000 nop
4017dc: 8c430000 lw v1,0(v0)
4017e0: 8fc20020 lw v0,32(s8)
4017e4: 00000000 nop
4017e8: 8c420008 lw v0,8(v0)
4017ec: 00000000 nop
4017f0: 8c420000 lw v0,0(v0)
4017f4: 00000000 nop
4017f8: 0062102a slt v0,v1,v0 # 比较重排后链表前后两个数的大小,升序则爆炸
4017fc: 10400015 beqz v0,401854 <phase_6+0x354>
401800: 00000000 nop
401804: 0c10087c jal 4021f0 <explode_bomb>
401808: 00000000 nop
40180c: 8fdc0010 lw gp,16(s8)
401810: 10000010 b 401854 <phase_6+0x354>
401814: 00000000 nop
401818: 8fc20020 lw v0,32(s8)
40181c: 00000000 nop
401820: 8c430000 lw v1,0(v0)
401824: 8fc20020 lw v0,32(s8)
401828: 00000000 nop
40182c: 8c420008 lw v0,8(v0)
401830: 00000000 nop
401834: 8c420000 lw v0,0(v0)
401838: 00000000 nop
40183c: 0043102a slt v0,v0,v1 # 比较重排后链表前后两个数的大小,降序则爆炸
401840: 10400004 beqz v0,401854 <phase_6+0x354>
401844: 00000000 nop
401848: 0c10087c jal 4021f0 <explode_bomb>
40184c: 00000000 nop
401850: 8fdc0010 lw gp,16(s8)
401854: 8fc20020 lw v0,32(s8)
401858: 00000000 nop
40185c: 8c420008 lw v0,8(v0)
401860: 00000000 nop
401864: afc20020 sw v0,32(s8)
401868: 8fc2001c lw v0,28(s8)
40186c: 00000000 nop
401870: 24420001 addiu v0,v0,1 # i++
401874: afc2001c sw v0,28(s8)
401878: 8fc2001c lw v0,28(s8)
40187c: 00000000 nop
401880: 28420005 slti v0,v0,5 # i < 5
401884: 1440ffcb bnez v0,4017b4 <phase_6+0x2b4>
401888: 00000000 nop
40188c: 03c0e821 move sp,s8
401890: 8fbf005c lw ra,92(sp)
401894: 8fbe0058 lw s8,88(sp)
401898: 27bd0060 addiu sp,sp,96
40189c: 03e00008 jr ra
4018a0: 00000000 nop
phase_secret
在炸弹四输入5 austinpowers即可进入隐藏炸弹。这个炸弹就是一个普通的二叉搜索树,输入数值x,执行find(x),返回得到根节点到值为x的节点的路径。炸弹要求返回值为7=111B,即根节点的右儿子节点的右儿子节点的右儿子节点,该节点值为1001。因此输入1001即可。
00402264 <phase_defused>:
402264: 27bdff88 addiu sp,sp,-120
402268: afbf0074 sw ra,116(sp)
40226c: afbe0070 sw s8,112(sp)
402270: 03a0f021 move s8,sp
402274: 3c1c0042 lui gp,0x42
402278: 279cb190 addiu gp,gp,-20080
40227c: afbc0010 sw gp,16(sp)
402280: 3c020041 lui v0,0x41
402284: 8c433240 lw v1,12864(v0)
402288: 24020006 li v0,6
40228c: 14620039 bne v1,v0,402374 <phase_defused+0x110>
402290: 00000000 nop
402294: 8f828058 lw v0,-32680(gp)
402298: 00000000 nop
40229c: 244400f0 addiu a0,v0,240
4022a0: 3c020040 lui v0,0x40
4022a4: 244328a8 addiu v1,v0,10408 # "%d %s" !!!
4022a8: 27c20068 addiu v0,s8,104
4022ac: 00602821 move a1,v1
4022b0: 00403021 move a2,v0
4022b4: 27c20018 addiu v0,s8,24
4022b8: 00403821 move a3,v0
4022bc: 8f828084 lw v0,-32636(gp)
4022c0: 00000000 nop
4022c4: 0040c821 move t9,v0
4022c8: 0320f809 jalr t9 # 调用库中函数sscanf !!!
4022cc: 00000000 nop
4022d0: 8fdc0010 lw gp,16(s8)
4022d4: 00401821 move v1,v0
4022d8: 24020002 li v0,2 # 判断sscanf读得的有效数据个数是否为2
4022dc: 1462001d bne v1,v0,402354 <phase_defused+0xf0>
4022e0: 00000000 nop
4022e4: 27c20018 addiu v0,s8,24
4022e8: 00402021 move a0,v0 # $a0中存储着输入的字符
4022ec: 3c020040 lui v0,0x40
4022f0: 244528b0 addiu a1,v0,10416 # $a1中存储着"austinpowers"
4022f4: 0c10073e jal 401cf8 <strings_not_equal> # 判断是否相等
4022f8: 00000000 nop
4022fc: 8fdc0010 lw gp,16(s8)
402300: 14400014 bnez v0,402354 <phase_defused+0xf0>
402304: 00000000 nop
402308: 3c020040 lui v0,0x40
40230c: 244428c0 addiu a0,v0,10432
402310: 8f828038 lw v0,-32712(gp)
402314: 00000000 nop
402318: 0040c821 move t9,v0
40231c: 0320f809 jalr t9
402320: 00000000 nop
402324: 8fdc0010 lw gp,16(s8)
402328: 3c020040 lui v0,0x40
40232c: 244428e8 addiu a0,v0,10472
402330: 8f828038 lw v0,-32712(gp)
402334: 00000000 nop
402338: 0040c821 move t9,v0
40233c: 0320f809 jalr t9
402340: 00000000 nop
402344: 8fdc0010 lw gp,16(s8)
402348: 0c100664 jal 401990 <secret_phase> # 跳转至secret_phase
40234c: 00000000 nop
402350: 8fdc0010 lw gp,16(s8)
402354: 3c020040 lui v0,0x40
402358: 24442920 addiu a0,v0,10528
40235c: 8f828038 lw v0,-32712(gp)
402360: 00000000 nop
402364: 0040c821 move t9,v0
402368: 0320f809 jalr t9
40236c: 00000000 nop
402370: 8fdc0010 lw gp,16(s8)
402374: 03c0e821 move sp,s8
402378: 8fbf0074 lw ra,116(sp)
40237c: 8fbe0070 lw s8,112(sp)
402380: 27bd0078 addiu sp,sp,120
402384: 03e00008 jr ra
402388: 00000000 nop
40238c: 00000000 nop
004018a4 <fun7>:
4018a4: 27bdffe0 addiu sp,sp,-32
4018a8: afbf001c sw ra,28(sp)
4018ac: afbe0018 sw s8,24(sp)
4018b0: 03a0f021 move s8,sp
4018b4: afc40020 sw a0,32(s8)
4018b8: afc50024 sw a1,36(s8)
4018bc: 8fc20020 lw v0,32(s8)
4018c0: 00000000 nop
4018c4: 14400004 bnez v0,4018d8 <fun7+0x34> # $v0($a0)不为0则继续,为0则函数结束
4018c8: 00000000 nop
4018cc: 2402ffff li v0,-1 # 设返回值为-1,即没有找到该值
4018d0: 10000029 b 401978 <fun7+0xd4>
4018d4: 00000000 nop
4018d8: 8fc20020 lw v0,32(s8) # 取出$a0中的值
4018dc: 00000000 nop
4018e0: 8c430000 lw v1,0(v0) # $v1 = m[$a0]
4018e4: 8fc20024 lw v0,36(s8) # $v0 = $a1
4018e8: 00000000 nop
4018ec: 0043102a slt v0,v0,v1 # $v0 >= $v1时函数跳转
4018f0: 1040000c beqz v0,401924 <fun7+0x80>
4018f4: 00000000 nop
4018f8: 8fc20020 lw v0,32(s8)
4018fc: 00000000 nop
401900: 8c420004 lw v0,4(v0) # 令fun7第一个参数为节点的左儿子的地址
401904: 00000000 nop
401908: 00402021 move a0,v0
40190c: 8fc50024 lw a1,36(s8) #第二个参数不变
401910: 0c100629 jal 4018a4 <fun7>
401914: 00000000 nop
401918: 00021040 sll v0,v0,0x1 # $v0左移一位
40191c: 10000016 b 401978 <fun7+0xd4>
401920: 00000000 nop
401924: 8fc20020 lw v0,32(s8)
401928: 00000000 nop
40192c: 8c430000 lw v1,0(v0)
401930: 8fc20024 lw v0,36(s8)
401934: 00000000 nop
401938: 0062102a slt v0,v1,v0 # $v1 >= $v0时函数跳转,即$v0 == $v1时找到节点,函数返回0
40193c: 1040000d beqz v0,401974 <fun7+0xd0>
401940: 00000000 nop
401944: 8fc20020 lw v0,32(s8)
401948: 00000000 nop
40194c: 8c420008 lw v0,8(v0) # 令fun7第一个参数为节点的右儿子的地址
401950: 00000000 nop
401954: 00402021 move a0,v0
401958: 8fc50024 lw a1,36(s8) # 第二个参数不变
40195c: 0c100629 jal 4018a4 <fun7>
401960: 00000000 nop
401964: 00021040 sll v0,v0,0x1 # $v0左移一位
401968: 24420001 addiu v0,v0,1 # $v0末位补1
40196c: 10000002 b 401978 <fun7+0xd4>
401970: 00000000 nop
401974: 00001021 move v0,zero
401978: 03c0e821 move sp,s8
40197c: 8fbf001c lw ra,28(sp)
401980: 8fbe0018 lw s8,24(sp)
401984: 27bd0020 addiu sp,sp,32
401988: 03e00008 jr ra
40198c: 00000000 nop
00401990 <secret_phase>:
401990: 27bdffd8 addiu sp,sp,-40
401994: afbf0024 sw ra,36(sp)
401998: afbe0020 sw s8,32(sp)
40199c: 03a0f021 move s8,sp
4019a0: 3c1c0042 lui gp,0x42
4019a4: 279cb190 addiu gp,gp,-20080
4019a8: afbc0010 sw gp,16(sp)
4019ac: 0c1007fb jal 401fec <read_line> # 输入
4019b0: 00000000 nop
4019b4: 8fdc0010 lw gp,16(s8)
4019b8: afc2001c sw v0,28(s8)
4019bc: 8fc2001c lw v0,28(s8)
4019c0: 00000000 nop
4019c4: 00402021 move a0,v0
4019c8: 00002821 move a1,zero
4019cc: 2406000a li a2,10
4019d0: 8f828070 lw v0,-32656(gp)
4019d4: 00000000 nop
4019d8: 0040c821 move t9,v0
4019dc: 0320f809 jalr t9
4019e0: 00000000 nop
4019e4: 8fdc0010 lw gp,16(s8)
4019e8: afc20018 sw v0,24(s8)
4019ec: 8fc20018 lw v0,24(s8)
4019f0: 00000000 nop
4019f4: 2442ffff addiu v0,v0,-1 # $v0--
4019f8: 2c4203e9 sltiu v0,v0,1001 # 判断[输入的值-1]($v0)是否小于1001,是则继续,否则引爆
4019fc: 14400004 bnez v0,401a10 <secret_phase+0x80>
401a00: 00000000 nop
401a04: 0c10087c jal 4021f0 <explode_bomb>
401a08: 00000000 nop
401a0c: 8fdc0010 lw gp,16(s8)
401a10: 3c020041 lui v0,0x41
401a14: 24443184 addiu a0,v0,12676 # fun7的第一个参数0x413814 m[0x413814] = 0x24 = 36
401a18: 8fc50018 lw a1,24(s8) # fun7的第二个参数,即输入的数
401a1c: 0c100629 jal 4018a4 <fun7> # 进入fun7
401a20: 00000000 nop
401a24: 8fdc0010 lw gp,16(s8)
401a28: 00401821 move v1,v0
401a2c: 24020007 li v0,7
401a30: 10620004 beq v1,v0,401a44 <secret_phase+0xb4> # fun7返回值为7 = 111B时才不会引爆
401a34: 00000000 nop
401a38: 0c10087c jal 4021f0 <explode_bomb>
401a3c: 00000000 nop
401a40: 8fdc0010 lw gp,16(s8)
401a44: 3c020040 lui v0,0x40
401a48: 244427b8 addiu a0,v0,10168
401a4c: 8f828038 lw v0,-32712(gp)
401a50: 00000000 nop
401a54: 0040c821 move t9,v0
401a58: 0320f809 jalr t9
401a5c: 00000000 nop
401a60: 8fdc0010 lw gp,16(s8)
401a64: 0c100899 jal 402264 <phase_defused>
401a68: 00000000 nop
401a6c: 8fdc0010 lw gp,16(s8)
401a70: 03c0e821 move sp,s8
401a74: 8fbf0024 lw ra,36(sp)
401a78: 8fbe0020 lw s8,32(sp)
401a7c: 27bd0028 addiu sp,sp,40
401a80: 03e00008 jr ra
401a84: 00000000 nop
总结
每个阶段对应的C++代码
只给出关键部分。简洁明了,一看就懂,理解炸弹大概流程用。
//输入ID
int ID;
cin>>ID;
phase_1
//input
string str;
cin>>str;
//phase_1
string ans = "Let's begin now!";
if (str == ans) return ;
else explode_bomb();
phase_2
//input
int a[6];
for (int i = 0;i < 6;i++)
cin>>a[i];
//phase_2
if (a[0] != 1) explode_bomb();
for (int i = 0;i < 6;i++)
if (a[i] * ((ID >> i) & 1) != a[i + 1])
explode_bomb();
phase_3
//input
int a[2];
char c
cin>>a[0]>>c>>a[1];
//phase_3
char c0;
int b;
switch(a[0]) {
case 0:c0 = 'q';b = 777;if ((ID & 1) * a[1] != b) explode_bomb();break;
case 1:c0 = 'b';b = 214;if ((ID & 1) * a[1] != b) explode_bomb();break;
case 2:c0 = 'b';b = 755;if ((ID & 1) * a[1] != b) explode_bomb();break;
case 3:c0 = 'k';if ((ID & 1) * a[1] != 0) explode_bomb();break;
case 4:c0 = 'o';b = 228;if ((ID & 1) * a[1] != b) explode_bomb();break;
case 5:c0 = 't';b = 513;if ((ID & 1) * a[1] != b) explode_bomb();break;
case 6:c0 = 'v';b = 780;if ((ID & 1) * a[1] != b) explode_bomb();break;
case 7:c0 = 'b';b = 824;if ((ID & 1) * a[1] != b) explode_bomb();break;
default: explode_bomb();
}
if (c != c0) explode_bomb();
phase_4
//input
int x;
cin>>x;
//fun4
int fun4(int x) {
if (x < 2) return 1;
return f(x - 1) + f(x - 2);
}
//phase_4
if (ID & 1) {
if (fun4(x) != 8) explode_bomb();
}
else {
if (fun4(x) != 13) explode_bomb();
}
phase_5
//input
char str[6];
cin>>str;
//phase_5
char res[6];
char S[16] = "isrveawhobpnutfg";
char ans[6] = "giants";
for (int i = 0;i < 6;i++) {
int pos = str[i] & 15;//15D = FH = 1111B
res[i] = S[pos];
}
for (int i = 0;i < 6;i++)
if (res[i] != ans[i])
explode_bomb();
phase_6
//input
int a[6];
for (int i = 0;i < 6;i++)
cin>>a[i];
//phase_6
for (int i = 0;i < 6;i++) {
if (!(i > 0 && i < 7) explode_bomb();
for (int j = i + 1;j < 6;j++)
if (a[i] == a[j]) explode_bomb();
}
chain c = {0x0fd, 0x2d5, 0x12d, 0x3e5, 0x0d4, 0x1b0};
chainNode res[6];
for (int i = 0;i < 6;i++) {
chainNode *node = c.firstNode;
for (int j = 1;j < a[i];j++)
node = node->next;
res[i] = node;
}
chainNode *node = c.firstNode;
for (int i = 1;i < 6;i++) {
node->next = res[i];
node = res[i];
}
node->next = null;
if (ID & 1) {
node = c.firstNode;
for (int i = 1;i < 6;i++)
if (node->element < node->next->element)
explode_bomb();
}
else {
node = c.firstNode;
for (int i = 1;i < 6;i++)
if (node->element > node->next->element)
explode_bomb();
}