/* * AddTest.c * * Created on: 2019年10月13日 * Author: appweb */ #include <stdio.h> int add(int a, int b) { int c = addAgain(a, b); return c; } int addAgain(int a, int b) { int c = a + b; return c; } int sub(int a, int b) { int c = a - b; return c; } int main() { int s = add(5, 3); int d = sub(5, 3); return 0; }
makefilehtml
PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) OBJS = AddTest.o # 若是在命令行直接执行make 须要export BUILD_MODE=debug 或者run ifeq ($(BUILD_MODE),debug) CFLAGS += -g else ifeq ($(BUILD_MODE),run) CFLAGS += -O2 else $(error Build mode $(BUILD_MODE) not supported by this Makefile) endif all: InvokeFunction # $@ 表示规则中的目标文件集。在模式规则中,若是有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。 # $^ 全部的依赖目标的集合。以空格分隔。若是在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。 # $< 依赖目标中的第一个目标名字。若是依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。 # $? 全部比目标新的依赖目标的集合。以空格分隔。 # 输出变量可使用以下办法 $(info $$OBJS is [${OBJS}]) $(info $$(CXX) is [$(CXX)]) $(info $$(PROJECT_ROOT) is [$(PROJECT_ROOT)]) AddTest: $(OBJS) $(CXX) -o $@ $^ %.o: $(PROJECT_ROOT)src/%.c $(CXX) -c $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -o $@ $< clean: rm -fr AddTest $(OBJS)
一如既往的使用CDT,寄存器监视(我须要观察的几个)、内存监视 、反编译的汇编指令窗口弄在一块儿,调试起来真是方便
打包好的工程web
开始调试shell
添加寄存器监视app
添加内存监视函数
启用指令单步调试测试
rsp
是栈顶
,rbp
是栈底
,大小及栈分配的生长方向以下:优化
栈分配生长方向 <-------------------------------------+ rsp 栈顶 rbp 栈底 +------------------+------------------+ | | | | | | +------------------+------------------+ 内存低位地址 内存高位地址
如今rsp是0xfffffffd750,执行完下图的ui
00000000000004195598: mov %rsp,%rbp 00000000000004195601: sub $0x10,%rsp
这两条汇编指令后,rbp是0xfffffffd750,rsp是0xfffffffd740,这就是 函数栈帧空间分配this
在执行完callq与push指令以后,栈顶再往前的内存(就是紧靠着栈顶比栈顶还小的内存)会发生变化,看图中内存监视器红色部分,按有些书上说法此处是保存了rip和rbp,可是我没能太理解,看数值不怎么能对上spa
注意看 进入addAagin方法后,并非像某些书上说的会分配函数栈帧控空间,我猜想是编译器作了优化吧,由于addAagin方法再也不调用其余方法了。
看了R大的文章,这种函数应该是 叶函数,叶函数是不调用别的函数的函数。
00000000000004195547: mov %edi,-0x14(%rbp) 00000000000004195550: mov %esi,-0x18(%rbp)
看上图,从edi和esi集群器向 相对于rbp(栈底)偏移(负偏移)的内存传数据,这个称之为压栈
不过有些书上讲的是 向 相对rsp(栈顶)偏移(正偏移)的内存传数据,我理解成一个意思,不过是内存定位的方式不一样罢了