Lab2 bomb

GDB手册

Enscript Output (cmu.edu) 1

1.单步执行和跟踪函数调用

#include <stdio.h>

int add_range(int low, int high)
{
	int i, sum;
	for (i = low; i <= high; i++)
		sum = sum + i;
	return sum;
}

int main(void)
{
	int result[100];
	result[0] = add_range(1, 10);
	result[1] = add_range(1, 100);
	printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);
	return 0;
}
result[0]=55
result[1]=5105

第二个有问题,因为sum未初始化,用的是第一次调用的寄存器

gcc -g main.c -o main
gdb main

-g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。gdb提供一个类似Shell的命令行环境,上面的(gdb)就是提示符,在这个提示符下输入help可以查看命令的类别

看bomb.pdf

in a moment of weakness : 一时心软

chapter Ⅲ

3.2 程序编码

gcc -Og -o p p1.c p2.c

-Og,告诉编译器产生符合原始C代码整体结构的机器代码的优化等级。使用较高级别优化产生的代码会严重变形,以至于产生的机器代码和初始源代码之间的关系非常难以理解。因此我们会使用-Og优化作为学习工具。

首先C预处理器扩展源代码,插入所以用#include 命令指定的文件,并扩展所有用#define声明指定的宏。

其次,编译器 ()产生两个源代码的汇编文件,p1.s,p2.s.

接下来,汇编器()产生两个汇编代码转化成二进制目标代码文件p1.o,p2.o.

目标代码是机器代码的一种,它包含机器指令的所有形式,但是还没有填入全局值的地址。

最后,链接器将两个目标代码文件与实现库函数的代码合并,并产生最终的可执行代码文件 p,(由命令行指示符-o p指定的)

3.2.1 机器代码

  • 程序计数器(PC),%rip
  • 整数寄存器
  • 条件码寄存器

3.2.2 代码示例

gcc -Og -S mstore.c
gcc -Og -c mstore.c

3.7 过程

//前面的控制看看就行,记不下来,得查表

3.7.1 运行时栈

当函数过程需要的存储空间超过了寄存器能够存放的大小,就会在栈上分配空间,这个部分被称为frame(栈帧)

image-20220119155733170.png

image-20220119155747848.png

image-20220119155833946.png

bomb lab

some tips

gdb bomb 

在gdb中运行bomb程序

gdb bomb -tui

可以一遍看汇编代码一遍运行bomb程序

objdump -d bomb > bomb.txt

在shell中可以先反汇编bomb程序,并且重定向到bomb.txt中,便于查看结果。

利用Ctrl+F,搜索bomb相关字眼,可以看到explode_bomb,约莫是会导致炸弹的函数,你再通过gdb bomb -tui,运行程序时候,看着汇编一行行变换,发现还真是。

gdb :  disas

在gdb状态下如果你想要看一下当前的运行的汇编语句,如上。

image-20220119210930904.png

break explode_bomb
break phase_1
break phase_2
...

嗯,看看代码文件,这些是我们需要打的断点。

run ./sol.txt
## 就是拿txt里的东西来作为程序参数

phase_4

phase3 phase4,都是把要输入的值放在了栈上面

对于phase4扫一眼,

000000000040100c <phase_4>:
  40100c:	48 83 ec 18          	sub    $0x18,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax
  40102c:	75 07                	jne    401035 <phase_4+0x29>
  40102e:	83 7c 24 08 0e       	cmpl   $0xe,0x8(%rsp)
  401033:	76 05                	jbe    40103a <phase_4+0x2e>
  401035:	e8 00 04 00 00       	callq  40143a <explode_bomb>
  40103a:	ba 0e 00 00 00       	mov    $0xe,%edx
  40103f:	be 00 00 00 00       	mov    $0x0,%esi
  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi
  401048:	e8 81 ff ff ff       	callq  400fce <func4>
  40104d:	85 c0                	test   %eax,%eax
  40104f:	75 07                	jne    401058 <phase_4+0x4c>
  401051:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp)
  401056:	74 05                	je     40105d <phase_4+0x51>
  401058:	e8 dd 03 00 00       	callq  40143a <explode_bomb>
  40105d:	48 83 c4 18          	add    $0x18,%rsp
  401061:	c3                   	retq   

scanf输入函数需要字符类型作为参数,注意到 mov $0x4025cf, %esi 非常奇怪,因此

image-20220119205901143.png

该操作可以从CMU的gdb手册中看到.

image-20220119210020499.png

可以发现输入函数接受了两个整数.

  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax

同时这两行可以佐证该观点.

另外还得搞清楚

0000000000400fce <func4>:
  400fce:	48 83 ec 08          	sub    $0x8,%rsp
  400fd2:	89 d0                	mov    %edx,%eax
  400fd4:	29 f0                	sub    %esi,%eax
  400fd6:	89 c1                	mov    %eax,%ecx
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx
  400fdb:	01 c8                	add    %ecx,%eax
  400fdd:	d1 f8                	sar    %eax
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx
  400fe2:	39 f9                	cmp    %edi,%ecx
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401007:	48 83 c4 08          	add    $0x8,%rsp
  40100b:	c3                   	retq   

说实话,在gdb-tui里看的更清楚,那个是十进制的编号。

image-20220119225005967.png

/*复制的吴迪学长的代码,是将fun4人脑翻译成c,从前面可知x<=0xe,所以穷举一下就可以了*/
#include<stdio.h>
int fun(int a1, int a2, int x);
int fun(int a1, int a2, int x){
    int b = (a1 - a2) >> 31;
    int result = ((a1-a2) + b) >> 1;
    b = result + a2;
    if(b == x) return 0;
    if(b < x) {
        result = fun(a1, b + 1, x);
        return result * 2 + 1;
    }else{
        result = fun(b - 1, a2, x);
        return result * 2;
    }
}
int main(void){
    for(int i = 0; i <= 0xe; i++){
        if(fun(0xe,0,i) == 0){
            printf("%d\n",i) ;
        }
    }
    return 0; 
}

得出前一个值是0 1 3 7;从401051可以看出后一个值应该是0.

phase_5

lab4 Cache Lab

实现一个缓存系统

This lab will help you understand the impact that cache memories can have on the performance of your Cprograms

The lab consists of two parts. In the first part you will write asmall C program (about 200-300 lines) thatsimulates the behavior of a cache memory. In the second part,you will optimize a small matrix transposefunction, with the goal of minimizing the number of cache misses.

Part A: Writing a Cache Simulator


  1. 做bomb lab的时候可以看这个PDF来用gdb ↩︎