c:变参函数:汇编解析;va_list;marco 宏:__VA_ARGS__
文章目录
- 参考
- gcc 内部的宏定义
- 代码
- 汇编
- 调用
- 在 SEI CERT C++ Coding Standard 这个标准里
- 示例
- 实例
- 宏里的使用
参考
https://git.sr.ht/~gregkh/presentation-security/blob/3547183843399d693c35b502cf4a313e256d0dd8/security-stuff.pdf
gcc 内部的宏定义
宏定义:
使用的时builtin_va_end 宏定义。
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
使用到了下列内置函数来实现va-start、end、arg相关的宏。
/* Expand EXP, a call to __builtin_va_start. */static rtx
expand_builtin_va_start (tree exp)
{rtx nextarg;tree valist;location_t loc = EXPR_LOCATION (exp);
代码
int add(int first, int second, ... )
{int r=first + second;va_list va;;;va_start(va, second);while(int v= va_arg(va,int)){r+=v;}va_end(va);return r;
}
汇编
962 0000000000400c56 <add(int, int, ...)>:963 400c56: 55 push %rbp964 400c57: 48 89 e5 mov %rsp,%rbp965 400c5a: 48 83 ec 68 sub $0x68,%rsp 申请的栈空间是 0x68,但是使用的远远大于这个值。966 400c5e: 89 bd 2c ff ff ff mov %edi,-0xd4(%rbp) 六个寄存器参数都用上了967 400c64: 89 b5 28 ff ff ff mov %esi,-0xd8(%rbp) 而且将这六个参数放到超远的栈上。968 400c6a: 48 89 95 60 ff ff ff mov %rdx,-0xa0(%rbp)969 400c71: 48 89 8d 68 ff ff ff mov %rcx,-0x98(%rbp)970 400c78: 4c 89 85 70 ff ff ff mov %r8,-0x90(%rbp)971 400c7f: 4c 89 8d 78 ff ff ff mov %r9,-0x88(%rbp)972 400c86: 84 c0 test %al,%al 看着调用一直时0,是否用到floating 的变量?几个973 400c88: 74 20 je 400caa <add(int, int, ...)+0x54> 如果又floating的数值,将floating寄存器的值放到 栈974 400c8a: 0f 29 45 80 movaps %xmm0,-0x80(%rbp) floating的值放到floating 寄存器。975 400c8e: 0f 29 4d 90 movaps %xmm1,-0x70(%rbp)976 400c92: 0f 29 55 a0 movaps %xmm2,-0x60(%rbp)977 400c96: 0f 29 5d b0 movaps %xmm3,-0x50(%rbp)978 400c9a: 0f 29 65 c0 movaps %xmm4,-0x40(%rbp)979 400c9e: 0f 29 6d d0 movaps %xmm5,-0x30(%rbp)980 400ca2: 0f 29 75 e0 movaps %xmm6,-0x20(%rbp)981 400ca6: 0f 29 7d f0 movaps %xmm7,-0x10(%rbp)982 400caa: 8b 95 2c ff ff ff mov -0xd4(%rbp),%edx983 400cb0: 8b 85 28 ff ff ff mov -0xd8(%rbp),%eax984 400cb6: 01 d0 add %edx,%eax 第一个和第二个参数相加放到eax985 400cb8: 89 85 4c ff ff ff mov %eax,-0xb4(%rbp) 然后放到 栈986 400cbe: c7 85 30 ff ff ff 10 movl $0x10,-0xd0(%rbp) 将16 放到 栈987 400cc5: 00 00 00988 400cc8: c7 85 34 ff ff ff 30 movl $0x30,-0xcc(%rbp) 将0x30 放到栈989 400ccf: 00 00 00990 400cd2: 48 8d 45 10 lea 0x10(%rbp),%rax 将rbp + 16 的值放到rax,使用到了上一个函数栈。991 400cd6: 48 89 85 38 ff ff ff mov %rax,-0xc8(%rbp) ,放到栈992 400cdd: 48 8d 85 50 ff ff ff lea -0xb0(%rbp),%rax 将rbp -0xb0的地址放到rax993 400ce4: 48 89 85 40 ff ff ff mov %rax,-0xc0(%rbp) 放到栈994 400ceb: 8b 85 30 ff ff ff mov -0xd0(%rbp),%eax 将rbp-0xd0的值放到eax995 400cf1: 83 f8 2f cmp $0x2f,%eax 对比0x2f 为什么比对2f?996 400cf4: 77 23 ja 400d19 <add(int, int, ...)+0xc3>997 400cf6: 48 8b 85 40 ff ff ff mov -0xc0(%rbp),%rax998 400cfd: 8b 95 30 ff ff ff mov -0xd0(%rbp),%edx999 400d03: 89 d2 mov %edx,%edx1000 400d05: 48 01 d0 add %rdx,%rax1001 400d08: 8b 95 30 ff ff ff mov -0xd0(%rbp),%edx1002 400d0e: 83 c2 08 add $0x8,%edx1003 400d11: 89 95 30 ff ff ff mov %edx,-0xd0(%rbp)1004 400d17: eb 12 jmp 400d2b <add(int, int, ...)+0xd5>1005 400d19: 48 8b 85 38 ff ff ff mov -0xc8(%rbp),%rax1006 400d20: 48 8d 50 08 lea 0x8(%rax),%rdx1007 400d24: 48 89 95 38 ff ff ff mov %rdx,-0xc8(%rbp)1008 400d2b: 8b 00 mov (%rax),%eax1009 400d2d: 89 85 48 ff ff ff mov %eax,-0xb8(%rbp)1010 400d33: 83 bd 48 ff ff ff 00 cmpl $0x0,-0xb8(%rbp)1011 400d3a: 74 0e je 400d4a <add(int, int, ...)+0xf4>1012 400d3c: 8b 85 48 ff ff ff mov -0xb8(%rbp),%eax1013 400d42: 01 85 4c ff ff ff add %eax,-0xb4(%rbp) 将 eax 加到栈里1014 400d48: eb a1 jmp 400ceb <add(int, int, ...)+0x95>1015 400d4a: 8b 85 4c ff ff ff mov -0xb4(%rbp),%eax 最终的结果放到eax1016 400d50: c9 leaveq1017 400d51: c3 retq
调用
int main()
{
printf( "abc=%d\n", add(1,3,4,5,8,9,10);
return 1;
}
0000000000400968 <main>:400968: 55 push %rbp400969: 48 89 e5 mov %rsp,%rbp40096c: 48 83 ec 08 sub $0x8,%rsp 按16 字节对齐。多8个字节占栈,如果多出来一个参数400970: 6a 0a pushq $0xa400972: 41 b9 09 00 00 00 mov $0x9,%r9d400978: 41 b8 08 00 00 00 mov $0x8,%r8d40097e: b9 05 00 00 00 mov $0x5,%ecx400983: ba 04 00 00 00 mov $0x4,%edx400988: be 03 00 00 00 mov $0x3,%esi40098d: bf 01 00 00 00 mov $0x1,%edi400992: b8 00 00 00 00 mov $0x0,%eax 把 eax 清空400997: e8 aa fe ff ff callq 400846 <add(int, int, ...)>40099c: 48 83 c4 10 add $0x10,%rsp 释放栈4009a0: 89 c6 mov %eax,%esi4009a2: bf b2 0a 40 00 mov $0x400ab2,%edi4009a7: b8 00 00 00 00 mov $0x0,%eax4009ac: e8 3f fd ff ff callq 4006f0 <printf@plt>4009b1: b8 01 00 00 00 mov $0x1,%eax4009b6: c9 leaveq4009b7: c3 retq
在 SEI CERT C++ Coding Standard 这个标准里
提到了更安全的C++定义方式。 这种方式将编程从运行时变参,转移到了编译时,更安全。
示例
https://en.cppreference.com/w/cpp/language/parameter_pack
#include <iostream>void tprintf(const char* format) // base function
{std::cout << format;
}
、、 这个会产生多少个函数来?
template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // recursive variadic function
{for ( ; *format != '\0'; format++ ) {if ( *format == '%' ) {std::cout << value;tprintf(format+1, Fargs...); // recursive callreturn;}std::cout << *format;}
}int main()
{tprintf("% world% %\n","Hello",'!',123);
}
实例
变参传递到另一个函数里:
static inline void abc(int level, const char *format, ...)
{char buff[UMAX_LOG_SIZE];int msgLen;va_list arglist;memset(buff, 0, sizeof(buff));va_start(arglist, format);msgLen = vsnprintf(buff, UMAX_LOG_SIZE, format, arglist);va_end(arglist);
宏里的使用
下面这个宏,只包含有,三个点所代表的参数;不包含三个点以外有名称的参数。
__VA_ARGS__
#define _FUNC1_(tn, constness, ct, Method, ...) \
class mock_##Method { \
public:\RESULT_(tn, __VA_ARGS__) ct Method( \ // 这里__VA_ARGS__, 不包含 tn,constness,ct和Method
相关文章:
c:变参函数:汇编解析;va_list;marco 宏:__VA_ARGS__
文章目录 参考gcc 内部的宏定义代码汇编调用在 SEI CERT C Coding Standard 这个标准里示例实例宏里的使用 参考 https://git.sr.ht/~gregkh/presentation-security/blob/3547183843399d693c35b502cf4a313e256d0dd8/security-stuff.pdf gcc 内部的宏定义 宏定义:…...

eclipse安装教程(2021版)
第一步:下载JDK (下载地址) Java SE - Downloads 第二步 根据自己电脑的系统,选择相应的版本x64代表64位,x86代表32位。点击相应的JDK进行下载 点击之后会出现一个对话框 同意之后下载。(记住下载到哪,打…...

计算机网络重点概念整理-第二章 物理层【期末复习|考研复习】
第二章 物理层 【期末复习|考研复习】 计算机网络系列文章传送门: 第一章 计算机网络概述 第二章 物理层 第三章 数据链路层 第四章 网络层 第五章 传输层 第六章 应用层 第七章 网络安全 计算机网络整理-简称&缩写 文章目录 第二章 物理层 【期末复习|考研复习…...

【计算机网络】从输入URL到页面都显示经历了什么??
文字总结 ① DNS 解析:当用户输入一个网址并按下回车键的时候,浏览器获得一个域名,而在实际通信过程中,我们需要的是一个 IP 地址,因此我们需要先把域名转换成相应 IP 地址。浏览器会首先从缓存中找是否存在域名&…...

[C++]——带你学习类和对象
类和对象——上 目录:一、面向过程和面向对象二、类的概念三、类的访问限定符和封装3.1 访问限定符3.2 封装 四、类的作用域五、类的实例化六、类的对象大小的计算七、类成员函数this指针7.1 this指针的引用7.2 this 指针的特性 目录: 类和对象是很重要…...
Docker多平台、跨平台编译打包
大多数带有Docker官方标识的镜像都提供了多架构支持。如:busybox镜像支持amd64, arm32v5, arm32v6, arm32v7, arm64v8, i386, ppc64le, and s390x。当你在amd64设备上运行容器时,会拉取amd64镜像。 当你需要构建多平台镜像时,可以用 --platf…...

LLM系列 | 22 : Code Llama实战(下篇):本地部署、量化及GPT-4对比
引言 模型简介 依赖安装 模型inference 代码补全 4-bit版模型 代码填充 指令编码 Code Llama vs ChatGPT vs GPT4 小结 引言 青山隐隐水迢迢,秋尽江南草未凋。 小伙伴们好,我是《小窗幽记机器学习》的小编:卖热干面的小女孩。紧接…...

Nginx的进程结构实例演示
可以参考《Ubuntu 20.04使用源码安装nginx 1.14.0》安装nginx 1.14.0。 nginx.conf文件中worker_processes 2;这条语句表明启动两个worker进程。 sudo /nginx/sbin/nginx -c /nginx/conf/nginx.conf开启nginx。 ps -ef | grep nginx看一下进程情况。 sudo /nginx/sbin/ng…...
【Nginx36】Nginx学习:SSI静态文件服务器端包含模块
Nginx学习:SSI静态文件服务器端包含模块 这个模块让我想到了 2009 年刚刚工作的时候。最早我是做 .NET 的,而第一家公司其实是从 ASP 向 ASP.NET 转型中,因此,还是有不少的 ASP 做的页面。在那个时候,就用到了 SSI 。 …...

StripedFly恶意软件框架感染了100万台Windows和Linux主机
导语 近日,一款名为StripedFly的恶意软件框架在网络安全研究人员的监视之外悄然感染了超过100万台Windows和Linux系统。这款跨平台的恶意软件平台在过去的五年中一直未被察觉。在去年,卡巴斯基实验室发现了这个恶意框架的真实本质,并发现其活…...

蓝桥杯每日一题2023.10.25
乘积尾零 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 由于需要相乘的数很多,所以我们不能直接进行暴力模拟,我们知道10 2 * 5, 所以我们只需要找出这个数2和5的个数,其中2和5个数小的那个则为末尾0出现的个数 #include<bi…...

【C++】详解map和set基本接口及使用
文章目录 一、关联式容器与键值对1.1关联式容器(之前学的都是序列容器)1.2键值对pairmake_pair函数(map在插入的时候会很方便) 1.3树形结构的关联式容器 二、set2.1set的基本介绍2.1默认构造、迭代器区间构造、拷贝构造࿰…...
如何学习 Linux 内核内存管理
Linux内核内存管理部分是Linux内核中第二复杂的部分,但也非常有趣。学习它的最佳方法就是阅读代码。但在不了解术语和当前 mm 部分到底发生了什么的情况下,显然不能随意开始阅读代码。因此,我想这样开始学习比较好: 了解当前的 LS…...

【计算机网络】(谢希仁第八版)第一章课后习题答案
1.计算机网络可以向用户提供哪些服务? 答:例如音频,视频,游戏等,但本质是提供连通性和共享这两个功能。 连通性:计算机网络使上网用户之间可以交换信息,好像这些用户的计算机都可以彼此直接连…...
Operator开发之operator-sdk入门
1 operator-sdk 除了kubebuilder,operator-sdk是另一个常用的用于开发Operator的框架,不过operator-sdk还是基于kubebuilder,因此,通常还是建议使用kubebuilder开发Operator。 2 环境准备 跟kubebuilder类似,需要安…...

RabbitMQ生产者的可靠性
目录 MQ使用时会出现的问题 生产者的可靠性 1、生产者重连 2、生产者确认 3、数据持久化 交换机持久化 队列持久化 消息持久化 LazyQueue懒加载 MQ使用时会出现的问题 发送消息时丢失: 生产者发送消息时连接MQ失败生产者发送消息到达MQ后未找到Exchange生…...

集群节点批量执行 shell 命令
1、SSH 工具本身支持多窗口 比如 MobaXterm: 2、编写脚本通过 ssh 在多台机器批量执行shell命令 创建 ssh_hosts 配置文件,定义需要批量执行的节点(必须能够通过 ssh 免密登录,且存在同名用户) vim ssh_hostsbig…...

fl studio21.2水果软件怎么设置中文?
FL Studio编曲软件真的是个神器,不过一开始打开看到全是英文,有点头大,对吧?其实切换成中文版超级简单,只需要几个步骤就搞定啦!我自己也是用中文版的,觉得用起来更得心应手,效率也提…...

.NET CORE 3.1 集成JWT鉴权和授权2
JWT:全称是JSON Web Token是目前最流行的跨域身份验证、分布式登录、单点登录等解决方案。 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。 授权:这是使用JWT的…...
nbcio-boot如何进行gitee第三方登录
更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: https://gitee.com/nbacheng/nbcio-boot 前端代码:https://gitee.com/nbacheng/nbcio-vue.git 在线演示(包括H5) : http://122.227.135.243:9888 1、用户g…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...