簡單的main方法調用一個加減法函數背後的細節

測試程序

/*
 * 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(棧頂)偏移(正偏移)的內存傳數據,我理解成一個意思,不過是內存定位的方式不一樣罷了























相關文章
相關標籤/搜索