测试当前C环境的栈帧增长方向以及传递参数时的压栈顺序
前文链接:上次由于一个很常见的printf-bug(下文有提及)引发了我对栈的思考,并写下了一点总结。这次就尝试对不同的C环境进行实践,检测其传递参数的一些性质。
这是今天写的检查C环境的一段程序、能够判断环境的大小端、栈帧增长方向、传递参数时的压栈顺序、以及参数的求值顺序。
代码如下:
#include <stdio.h>
#include <assert.h>
#include <inttypes.h>
typedef const char *string_literal;
string_literal Endian() {
union {
uint16_t u16;
uint8_t u8; /* if FF small endian */
} u = {.u16 = 0x00FF};
return u.u8 ? "Small Endian" : "Big Endian";
}
enum {H2L, L2H} SD;
string_literal StackFrameDirection()
{
static string_literal *addr;
string_literal rtn;
return !addr ? addr = &rtn, rtn = StackFrameDirection(), addr = NULL, rtn
: &rtn < addr ? SD = H2L , "High -> Low" : (SD = L2H, "Low -> High");
}
enum {R2L, L2R} APO;
string_literal ArgumentsPushOrder(int a, int b)
{
(void)StackFrameDirection();
return (APO = !!SD ^ (&a > &b) ? L2R : R2L) ? "Left -> Right" : "Right -> Left";
}
string_literal ArgumentsEvaluationOrder(int a, int b)
{
return a < b ? "Left -> Right" : "Right -> Left";
}
int a_arg() {
static int cnt;
return ++cnt;
}
int main()
{
printf("In this C implementation:\n");
printf("\tEndian: %s\n", Endian());
printf("\tStackFrameDirection: %s\n", StackFrameDirection());
printf("\tArgumentsPushOrder: %s\n", ArgumentsPushOrder(a_arg(), a_arg()));
/* Evaluation Order below is determined by Complier and maybe not always same */
printf("\tArgumentsEvaluationOrder: %s\n", ArgumentsEvaluationOrder(a_arg(), a_arg()));
return 0;
}
我在macOS(intel)上以及树莓派OS(ARM Cortex-A)上都是这个结果:
In this C implementation:
Endian: Small Endian
StackFrameDirection: High -> Low
ArgumentsPushOrder: Left -> Right
ArgumentsEvaluationOrder: Left -> Right
在某咸鱼的 win10(intel) mingw 上的结果:
In this C implementation:
Endian: Small Endian
StackFrameDirection: High -> Low
ArgumentsPushOrder: Right -> Left
ArgumentsEvaluationOrder: Right -> Left
!!只有压栈顺序不一样。
Win下的压栈顺序和 WIN32 缓冲区溢出的知识相互照应了。
树莓派的压栈顺序又和学 ARM 的 ATPCS 相互照应了。
所以上次在树莓派(ILP32)上的异常结果的具体原因可以尝试分析一下了:
int64_t i = 1;
printf("%ld\n", i); // "%" PRId32
$ ./a.out
0
$
因为树莓派上的 GCC 的数据模型为 ILP32,
所以 printf("%ld\n", i); 可以简化成 F(P32, LL64);;
假设 P32 为 0xFFFFFCD0 , LL64 为 1 即 0x0000000000000001;
因为参数从左边开始压入栈中,且为小端模式,树莓派的栈是从高地址端向低地址端增长,
所以传递参数的时候字节的压栈顺序是 FF FF FC D0 00 00 00 00 00 00 00 01;
按照 C 传递参数以及可变参数 stdarg.h 的原理,printf 会根据 P32 的内容,把更低地址的四个字节00 00 00 00理解成 long 并输出,所以最后输出了0。
思考:前文检测的规律是有标准的吗?那又是谁制定的呢?
嗯,ATPCS 是否会在 Linux 上起作用,这点真不好说。
假如编译器有自己的传参标准的话,那系统调用怎么处理?
编译器肯定要遵循某种操作系统决定的标准。
可能编译器为了优化,会选择在程序内部的调用使用自己的标准?
测试当前C环境的栈帧增长方向以及传递参数时的压栈顺序的更多相关文章
- 大端小端系统_union_栈的增长方向
一道题引发的思考: 1.看一下之前写的union的特点,理解一下共享内存的概念 2.栈的增长方向是从高地址向低地址增长(数组比较特别,a[0]在低地址,a[n-1]在高地址)(堆由低地址到高地址存储) ...
- Windows x64 栈帧结构
0x01 前言 Windows 64位下函数调用约定变为了快速调用约定,前4个参数采用rcx.rdx.r8.r9传递,多余的参数从右向左依次使用堆栈传递.本次文章是对于Windows 64位下函数调用 ...
- c函数调用过程原理及函数栈帧分析
转载自地址:http://blog.csdn.net/zsy2020314/article/details/9429707 今天突然想分析一下函数在相互调用过程中栈帧的变化,还是想尽量以比 ...
- JAVA栈帧
简介 Java栈是一块线程私有的内存空间.java堆和程序数据相关,java栈就是和线程执行密切相关的,线程的执行的基本行为是函数调用,每次函数调用的数据都是通过java栈来传递的. Java栈与数据 ...
- 汇编3栈帧,参数传递,串操作,混合汇编,x64,asm文件
基础知识2 选择结构 通过判断 + 条件跳转指令来实现 循环结构 通过判断 + 条件跳转指令来实现(会有一个向上跳转的语句) 函数调用约定 C调用约定: 由外部平衡栈 标准调用约定 : 由函数内部平衡 ...
- 图解JVM字节码执行引擎之栈帧结构
一.执行引擎 “虚拟机”的概念是相对于“物理机”而言的,这两种“机器”都有执行代码的能力.物理机的执行引擎是直接建立在硬件处理器.物理寄存器.指令集和操作系统层面的:而“虚拟机”的执行引擎是 ...
- 栈帧%ebp,%esp详解
首先应该明白,栈是从高地址向低地址延伸的.每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息.寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部( ...
- Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)
Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...
- 栈帧 2.6. Frames 虚拟机内存模型
https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-2.html#jvms-2.6 小结: 1. https://docs.oracle. ...
随机推荐
- macbook pro上安装虚拟机
第一步:下载MacHunter的app应用商店 第二步:在MacHunter内下载Parallels Desktop虚拟机 第三步:如果在这个商店下载不下来,在网络资源上直接下载Parallels D ...
- Mixing Milk
链接 分析:水题,按照价格从小到大排序,在进行贪心即可 /* PROB:milk ID:wanghan LANG:C++ */ #include "iostream" #inclu ...
- 哈希表的C实现(一)
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...
- Laravel配置nginx环境
前言: 之前坑的!一直在尝试配置,但都失败了,只能用着apache,但是最近想整合swoole到laravel,无奈当前测试服务器是nginx,我只能再尝试在nginx上搭laravel环境 方法如下 ...
- cocos2dx-js 初探 整体流程helloworld.html分析
我们下载的是cocos2dx-js的精简版本,主要是为了分析简单明了,能更清楚的看到架构流程.下载地址:http://cocos2d-x.org/filecenter/jsbuilder/下载轻量版. ...
- 打印斐波那契(Fibonacci)数列
需求:打印 Fibonacci数列 思路: 当前项的值等于前两项数值的和 F=(F-1)+F(F-2) 样例: 输入:10 输出:1 1 2 3 5 8 13 21 34 55 辗转相加法实现 #in ...
- 【旧文章搬运】PE重定位表学习手记
原文发表于百度空间,2008-11-02========================================================================== 先定义一下 ...
- 把文件类型转化为byte[]
转自:https://blog.csdn.net/xinxiqi/article/details/78899159 package com.sanqing.util; import java.io.B ...
- 【204】显示3D大球球
1. 光滑球 From Jan 28, 2016 2. 大球球 https://www.revolvermaps.com/?target=enlarge&i=0xoqkxnu52c&a ...
- View Programming Guide for iOS ---- iOS 视图编程指南(三)---Windows
Windows Every iOS application needs at least one window—an instance of the UIWindow class—and some m ...