首页 > 其他分享 >结构体调用

结构体调用

时间:2024-08-02 08:57:06浏览次数:13  
标签:汇编 调用 代码 访问 编译器 MinGW 寄存器 结构

文章目录

前言

引言

由于开发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

说明

图片说明

本文章图片采取图床方式,图片可能失效(失效请联系[email protected])或者访问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三款编译器中结构体访问、函数访问均是以地址形式访问。

标签:汇编,调用,代码,访问,编译器,MinGW,寄存器,结构
From: https://blog.csdn.net/hongdiefatal/article/details/140743620

相关文章

  • 【数据结构】排序
    目录1.前言2.排序的概念及引用2.1排序的概念2.2常见的排序算法 3.常见排序算法的实现3.1插入排序3.1.1基本思想 3.1.2直接插入排序 3.1.3希尔排序(缩小增量排序)3.2选择排序3.2.1基本思想3.2.2直接选择排序3.2.3堆排序3.3交换排序3.3.1基本思想3.3.2冒泡排......
  • 数据结构经典测试题5
    1.intmain(){chararr[2][4];strcpy(arr[0],"you");strcpy(arr[1],"me");arr[0][3]='&';printf("%s\n",arr);return0;}上述代码输出结果是什么呢?A:you&meB:youC:meD:err答案为A因为arr是一个2行4列的二维数组,每一行可以存放最多三个......
  • 6.key的层级结构
    redis的key允许多个单词形成层级结构,多个单词之间用:隔开,格式如下:项目名:业务名:类型:id这个格式并非固定的,可以根据自己的需求来删除或添加词条。例如:taobao:user:1taobao:product:1如果value是一个java对象,例如一个user对象,则可以将其序列化为json字符串后存储:ta......
  • 4.Redis数据结构&通用命令
    Redis数据结构Redis是一个键值对的数据库。key:大多都是Stringvalue:类型多种多样 Redis通用命令keys:查看所有的key不建议在生产环境上使用keys命令,因为redis是单线程的,keys命令会搜索很长一段时间,搜索的期间redis无法执行其他的命令,等于服务被阻塞了,影响redis的性......
  • rpc请求调用
    RPC的请求调用一、远程过程调用(RPC)RPC(RemoteProcedureCall,远程过程调用)是客户端与区块链系统交互的一套协议和接口。用户通过RPC接口可查询区块链相关信息(如块高、区块、节点连接等)和发送交易。1.名词解释JSON(JavaScriptObjectNotation):一种轻量级的数据交换格......
  • 【每日一题 | 数据结构】时间复杂度计算
    题目解题方法对于二重循环求时间复杂度:写出外层i的变化值写出内层循环语句执行次数(看j)对次数求和找到频度和n的关系笔记视频跳转:【每日一题|数据结构】时间复杂度计算......
  • 数据结构----树,二叉树,哈夫曼树相关概念及其实现
    树形结构概述1分层逻辑结构所谓的分层逻辑结构,也称为树形逻辑结构关系,是数据结构中的一种逻辑关系结构,在该逻辑结构关系中的数据元素之间满足一对多的逻辑结构关系:起始数据节点有且仅有一个,没有直接前驱,可以有多个直接后继;末尾数据节点可以多个,有且仅有一个直接前驱,......
  • 分支结构
    分支结构if语句:格式:if(条件表达式){//条件为true时执行的代码}else{//条件为false时执行的代码}使用:基于条件是否为真或假来选择执行不同的代码块。if...elseif...else语句:格式:if(条件1){//条件1为true时执行的代码}els......
  • 循环结构
    循环结构for循环:格式:for(初始化表达式;条件表达式;更新表达式){//循环体}使用:适合于已知循环次数的情况。while循环:格式:while(条件表达式){//循环体}使用:适合于循环次数未知,但需要在循环开始前检查条件的情况。do-while循环:......
  • 数据结构与算法 - 递归
    一、递归1. 概述定义:在计算机科学中,递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集。比如单链表递归遍历的例子:voidf(Nodenode){if(node==null){return;}println("before:"+node.value)f(node.next);pr......