测试程序

/*
* 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;
}

makefile

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,寄存器监视(我需要观察的几个)、内存监视 、反编译的汇编指令窗口弄在一起,调试起来真是方便

打包好的工程

先编译下然后开始调试并观察



开始调试





添加寄存器监视



添加内存监视



启用指令单步调试



rsp栈顶rbp栈底,大小及栈分配的生长方向如下:

                     栈分配生长方向
<-------------------------------------+
rsp 栈顶 rbp 栈底
+------------------+------------------+
| | |
| | |
+------------------+------------------+
内存低位地址 内存高位地址

现在rsp是0xfffffffd750,执行完下图的

00000000000004195598:   mov     %rsp,%rbp
00000000000004195601: sub $0x10,%rsp

这两条汇编指令后,rbp是0xfffffffd750,rsp是0xfffffffd740,这就是 函数栈帧空间分配









在执行完callq与push指令之后,栈顶再往前的内存(就是紧靠着栈顶比栈顶还小的内存)会发生变化,看图中内存监视器红色部分,按有些书上说法此处是保存了rip和rbp,但是我没能太理解,看数值不怎么能对上

注意看 进入addAagin方法后,并不是像某些书上说的会分配函数栈帧控空间,我猜测是编译器做了优化吧,因为addAagin方法不再调用其他方法了。

看了R大的文章,这种函数应该是 叶函数,叶函数是不调用别的函数的函数。



00000000000004195547:   mov     %edi,-0x14(%rbp)
00000000000004195550: mov %esi,-0x18(%rbp)

看上图,从edi和esi集群器向 相对于rbp(栈底)偏移(负偏移)的内存传数据,这个称之为压栈

不过有些书上讲的是 向 相对rsp(栈顶)偏移(正偏移)的内存传数据,我理解成一个意思,不过是内存定位的方式不同罢了













































简单的main方法调用一个加减法函数背后的细节的更多相关文章

  1. [Inside HotSpot] hotspot的启动流程与main方法调用

    hotspot的启动流程与main方法调用 虚拟机的使命就是执行public static void main(String[])方法,从虚拟机创建到main方法执行会经过一系列流程.这篇文章详细讨论 ...

  2. 【M12】了解“抛出一个exception”与“传递一个参数”或“调用一个虚函数”之间的差异

    1.方法参数的声明语法和catch语句的语法是一样的,你可能会认为主调方法调用一个方法,并向其传递参数,与抛出一个异常传递到catch语句是一样的,是的,有相同之处,但也有更大的不同. 2.主调方法调 ...

  3. 从一个简单的main方法执行谈谈JVM工作机制

    本来JVM的工作原理浅到可以泛泛而谈,但如果真的想把JVM工作机制弄清楚,实在是很难,涉及到的知识领域太多.所以,本文通过简单的mian方法执行,浅谈JVM工作原理,看看JVM里面都发生了什么. 先上 ...

  4. python+selenium之中类/函数/模块的简单介绍和方法调用

    # coding=utf-8 class ClassA (object): string1 = "这是一个字符串." def instancefunc(self): print ( ...

  5. 使用main方法调用http请求本地服务器的某个servlet报错问题

    java.io.IOException: Server returned HTTP response code: 500 for URL: http://localhost:8081/test/myS ...

  6. java 主类的main方法调用其他方法

    方法1:A a=new test().new A(); 内部类对象通过外部类的实例对象调用其内部类构造方法产生,如下: public class test{ class A{ void fA(){ S ...

  7. C++调用一个成员函数的需求this指针的情况

    1.虚成员函数,因为需要this展望虚表指针的指针 2.在数据成员的操作部件的功能 #include "stdafx.h" #include <iostream> #i ...

  8. 用Main方法调用freemarker生成文件

    MyGenerator.java package com.comp.common; import java.io.BufferedWriter; import java.io.File; import ...

  9. java本地方法如何调用其他程序函数,方法详解

    JNI是Java Native Interface的缩写,中文为JAVA本地调用.从Java 1.1 开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许J ...

随机推荐

  1. 【翻译】.NET 5 Preview7发布

    今天,发布了.NET 5.0 Preview7.这是倒数第二个预览版本(在转移到RC之前).此时,大多数功能应该已经非常接近完成了.Single file和ARM64 intrinsics是两个花费了 ...

  2. 一张PDF了解JDK11 GC调优秘籍-附PDF下载

    目录 简介 废弃的VM选项 Source-File Mode Code Heap状态分析 AppCDS 总结 简介 JDK11相比JDK10,添加了一个新的Source-File Mode,可以直接通 ...

  3. 缓存利器、Lua模块下的共享内存

    上一节讲到了worker进程的共享内存,它利用丰富的指令使数据的缓存操作变得非常简单,但它也存在一些缺点. 1.worker进程之间会有锁竞争,在高并发的情况下会增加性能开销.2.只支持Lua布尔值. ...

  4. vuex多多,怎么当好一个奶妈

    前言 vue 本身更偏向于 view 层的框架,尤大大并没有一开始就给他一个完整的 mvvm 架构. 在 vue 的世界里 vuex 是用来实现 mvvm 中关键的 vm 层(视图模型层),你甚至可以 ...

  5. myBatis源码解析-缓存篇(2)

    上一章分析了mybatis的源码的日志模块,像我们经常说的mybatis一级缓存,二级缓存,缓存究竟在底层是怎样实现的.此次开始分析缓存模块 1. 源码位置,mybatis源码包位于org.apach ...

  6. Python os.tmpfile() 方法

    概述 os.tmpfile() 方法用于返回一个打开的模式为(w+b)的临时文件对象,这文件对象没有文件夹入口,没有文件描述符,将会自动删除.高佣联盟 www.cgewang.com 语法 tmpfi ...

  7. PHP array_fill() 函数

    ------------恢复内容开始------------ 实例 用给定的键值填充数组: <?php$a1=array_fill(3,4,"blue");print_r($ ...

  8. PHP jdtogregorian() 函数

    ------------恢复内容开始------------ 实例 把格利高里历法的日期转换为儒略日计数,然后再转换回格利高里历法的日期: <?php$jd=gregoriantojd(6,20 ...

  9. IOFFSETOF ICONTAINEROF IQUEUE_ENTRY

    #include <iostream> #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #de ...

  10. Lambda表达式运行原理

    目录 一.创建测试样例 二.利用Java命令编译分析 三.文末 JDK8引入了Lambda表达式以后,对我们写代码提供了很大的便利,那么Lambda表达式是如何运用简单表示来达到运行效果的呢?今天,我 ...