结构体调用

前言

引言

由于开发AT芯片进行脉冲计数时发现使用参数为结构体参数时会导致脉冲计数减少,查看汇编代码发现该编译器O0汇编代码访问结构体数据达到19个机器周期。使用O2优化时还是需要10个机器周期左右,因此对C函数调用、参数访问产生疑问。因此使用gcc、MinGW、MSVC三款编译器查看在x86平台上函数调用与结构体访问方式。

环境

  • VS2022

  • Microsoft Visual C++ 2022

  • VSCode 版本: 1.91.1 (user setup)

  • gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)

  • VMware® Workstation 17 Pro

  • gcc 11.4.0

  • vim 8.2.2121(Ubuntu)

  • Ubuntu20.04

说明

图片说明

本文章图片采取图床方式,图片可能失效(失效请联系2892967406@qq.com)或者访问Hexo (hongdei.github.io)

x86汇编简易说明

指令说明示例(x86-64环境)
lea加载有效地址(Load Effective Address)。将操作数的有效地址(而非内存中的值)加载到目标寄存器中。lea rax, [rbx + 8*rcx]:将rbx寄存器的值加上rcx寄存器值的8倍,结果地址加载到rax寄存器。
mov数据传送。将源操作数的值传送到目标操作数。根据操作数大小,可以是movb(字节)、movw(字)、movl(双字)、movq(四字)等。mov rax, 123:将立即数123移动到rax寄存器。
mov dword ptr [rbx], eax:将eax寄存器的值移动到rbx指向的内存地址(32位)。
movq在x86-64架构中,用于移动64位(四字)数据。movq rax, rbx:将rbx寄存器的值移动到rax寄存器。
movw在x86架构中,用于移动16位(字)数据。在x86-64中较少直接使用,但可通过适当的前缀或操作数大小指示器使用。movw ax, bx(假设在16位或32位模式下):将bx寄存器的低16位值移动到ax寄存器。
call过程调用。将返回地址(紧随call指令后的指令地址)推送到栈上,并跳转到指定的函数或地址执行。call myFunction:调用名为myFunction的函数。
nop无操作(No Operation)。执行时什么也不做,常用于代码对齐、占位或调试目的。nop:不执行任何操作。

主要参考文件

vs下查看汇编代码_vs查看汇编代码-CSDN博客

结构体调用

在gcc、MinGW、MSVC三款编译器中结构体访问、函数访问均是以地址形式访问。

MSVC编译器

步骤

  • 创建测试项目
  • 设置断点
  • 查看汇编代码

测试说明

本次测试定义函数fun1,结构体mian_t,并在主函数main中调用fun1,MinGW与GCC编译器仅编译器不同,测试代码完全一致。

`#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

typedef struct

{

uint16_t a;

uint16_t b;

uint16_t c;

}main_t;

static void fun1(const main_t *t)

{

uint16_t a = t->a;

uint16_t b = t->b;

uint16_t c = t->c;

}

int main(int argc, char const *argv[])

{

main_t x;

x.a = 1;

x.b = 2;

x.c = 3;

fun1(&x);

printf(“%d %d %d\n”,x.a,x.b,x.c);

printf(“hello word\n”);

return 0;

}`

设置断点

VS可以在调试界面中查看程序汇编代码。在函数调用中设置断点(可以查看整个工程汇编代码)。
在这里插入图片描述

汇编代码

在调试选项中选择窗口->反汇编

在这里插入图片描述

函数调用

函数调用主要是通过lea和call命令实现(直接访问函数地址)。

在这里插入图片描述

结构体访问

结构体访问主要通过mov访问,通过lea传入结构体地址。

在这里插入图片描述

MinGW编译器

MinGW使用VSCode编写,VScode使用MinGW编译器见xxx(文章还没写)。

步骤

  • 创建测试项目

  • 编译

  • 查看汇编代码

测试项目

MSVC编译器->测试说明

编译

使用不优化、汇编输出源信息。

gcc .\main.c -S -fverbose-asm -O0 -o main1

汇编代码

通过leaq和movq实现函数参数传递、call实现函数调用(直接访问函数地址)。

在这里插入图片描述

在这里插入图片描述

GCC编译器

本人采用VM虚拟机运行Ubuntun系统。

步骤

  • 创建测试项目
  • 编译
  • 查看汇编代码

测试项目

MSVC编译器->测试说明

编译

MinGW编译器->编译

汇编代码

由于MinGW基于gcc编译器,因此在汇编代码上与MinGW基本一致。

在这里插入图片描述
在这里插入图片描述

结论

在gcc、MinGW、MSVC三款编译器中结构体访问、函数访问均是以地址形式访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值