当前位置: 首页 > news >正文

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 为什么比对2f996   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 内部的宏定义 宏定义&#xff1a;…...

eclipse安装教程(2021版)

第一步&#xff1a;下载JDK &#xff08;下载地址&#xff09; Java SE - Downloads 第二步 根据自己电脑的系统&#xff0c;选择相应的版本x64代表64位&#xff0c;x86代表32位。点击相应的JDK进行下载 点击之后会出现一个对话框 同意之后下载。(记住下载到哪&#xff0c;打…...

计算机网络重点概念整理-第二章 物理层【期末复习|考研复习】

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

【计算机网络】从输入URL到页面都显示经历了什么??

文字总结 ① DNS 解析&#xff1a;当用户输入一个网址并按下回车键的时候&#xff0c;浏览器获得一个域名&#xff0c;而在实际通信过程中&#xff0c;我们需要的是一个 IP 地址&#xff0c;因此我们需要先把域名转换成相应 IP 地址。浏览器会首先从缓存中找是否存在域名&…...

[C++]——带你学习类和对象

类和对象——上 目录&#xff1a;一、面向过程和面向对象二、类的概念三、类的访问限定符和封装3.1 访问限定符3.2 封装 四、类的作用域五、类的实例化六、类的对象大小的计算七、类成员函数this指针7.1 this指针的引用7.2 this 指针的特性 目录&#xff1a; 类和对象是很重要…...

Docker多平台、跨平台编译打包

大多数带有Docker官方标识的镜像都提供了多架构支持。如&#xff1a;busybox镜像支持amd64, arm32v5, arm32v6, arm32v7, arm64v8, i386, ppc64le, and s390x。当你在amd64设备上运行容器时&#xff0c;会拉取amd64镜像。 当你需要构建多平台镜像时&#xff0c;可以用 --platf…...

LLM系列 | 22 : Code Llama实战(下篇):本地部署、量化及GPT-4对比

引言 模型简介 依赖安装 模型inference 代码补全 4-bit版模型 代码填充 指令编码 Code Llama vs ChatGPT vs GPT4 小结 引言 青山隐隐水迢迢&#xff0c;秋尽江南草未凋。 小伙伴们好&#xff0c;我是《小窗幽记机器学习》的小编&#xff1a;卖热干面的小女孩。紧接…...

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学习&#xff1a;SSI静态文件服务器端包含模块 这个模块让我想到了 2009 年刚刚工作的时候。最早我是做 .NET 的&#xff0c;而第一家公司其实是从 ASP 向 ASP.NET 转型中&#xff0c;因此&#xff0c;还是有不少的 ASP 做的页面。在那个时候&#xff0c;就用到了 SSI 。 …...

StripedFly恶意软件框架感染了100万台Windows和Linux主机

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

蓝桥杯每日一题2023.10.25

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

【C++】详解map和set基本接口及使用

文章目录 一、关联式容器与键值对1.1关联式容器&#xff08;之前学的都是序列容器&#xff09;1.2键值对pairmake_pair函数&#xff08;map在插入的时候会很方便&#xff09; 1.3树形结构的关联式容器 二、set2.1set的基本介绍2.1默认构造、迭代器区间构造、拷贝构造&#xff0…...

如何学习 Linux 内核内存管理

Linux内核内存管理部分是Linux内核中第二复杂的部分&#xff0c;但也非常有趣。学习它的最佳方法就是阅读代码。但在不了解术语和当前 mm 部分到底发生了什么的情况下&#xff0c;显然不能随意开始阅读代码。因此&#xff0c;我想这样开始学习比较好&#xff1a; 了解当前的 LS…...

【计算机网络】(谢希仁第八版)第一章课后习题答案

1.计算机网络可以向用户提供哪些服务&#xff1f; 答&#xff1a;例如音频&#xff0c;视频&#xff0c;游戏等&#xff0c;但本质是提供连通性和共享这两个功能。 连通性&#xff1a;计算机网络使上网用户之间可以交换信息&#xff0c;好像这些用户的计算机都可以彼此直接连…...

Operator开发之operator-sdk入门

1 operator-sdk 除了kubebuilder&#xff0c;operator-sdk是另一个常用的用于开发Operator的框架&#xff0c;不过operator-sdk还是基于kubebuilder&#xff0c;因此&#xff0c;通常还是建议使用kubebuilder开发Operator。 2 环境准备 跟kubebuilder类似&#xff0c;需要安…...

RabbitMQ生产者的可靠性

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

集群节点批量执行 shell 命令

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

fl studio21.2水果软件怎么设置中文?

FL Studio编曲软件真的是个神器&#xff0c;不过一开始打开看到全是英文&#xff0c;有点头大&#xff0c;对吧&#xff1f;其实切换成中文版超级简单&#xff0c;只需要几个步骤就搞定啦&#xff01;我自己也是用中文版的&#xff0c;觉得用起来更得心应手&#xff0c;效率也提…...

.NET CORE 3.1 集成JWT鉴权和授权2

JWT&#xff1a;全称是JSON Web Token是目前最流行的跨域身份验证、分布式登录、单点登录等解决方案。 通俗地来讲&#xff0c;JWT是能代表用户身份的令牌&#xff0c;可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。 授权&#xff1a;这是使用JWT的…...

nbcio-boot如何进行gitee第三方登录

更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 1、用户g…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理&#xff1a;检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;RankRAG&#xff1a;Unifying Context Ranking…...

【Ftrace 专栏】Ftrace 参考博文

ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...

【技巧】dify前端源代码修改第一弹-增加tab页

回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码&#xff0c;在知识库增加一个tab页"HELLO WORLD"&#xff0c;完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…...

STL 2迭代器

文章目录 1.迭代器2.输入迭代器3.输出迭代器1.插入迭代器 4.前向迭代器5.双向迭代器6.随机访问迭代器7.不同容器返回的迭代器类型1.输入 / 输出迭代器2.前向迭代器3.双向迭代器4.随机访问迭代器5.特殊迭代器适配器6.为什么 unordered_set 只提供前向迭代器&#xff1f; 1.迭代器…...

LeetCode - 148. 排序链表

目录 题目 思路 基本情况检查 复杂度分析 执行示例 读者可能出的错误 正确的写法 题目 148. 排序链表 - 力扣&#xff08;LeetCode&#xff09; 思路 链表归并排序采用"分治"的策略&#xff0c;主要分为三个步骤&#xff1a; 分割&#xff1a;将链表从中间…...