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…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...