关于大小端以及GCC堆栈保护

一、大小端
写一段代码 测试机器是大端还是小端?
#include <stdio.h>
#include <stdlib.h>

int main()
{
        int a=0x12345678;
        char c=a;
        printf("c=%x \n",c);
        printf("exit...\n");
}


在linux上的运行结果:
在这里插入图片描述

输出结果c=78表示是小端模式 如果输出结果c=12则为大端模式

到底什么是大小端?

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致

在这里插入图片描述

对于十六进制数据ox12345678 低字节数据78存放在内存的低8位 0x12存放在内存的高8位(24~32) --小端模式 反之为大端模式

大小端现状

(1)Intel的80×86系列芯片使用小端存储模式
(2)ARM芯片默认采用小端,但可以切换为大端
(3)MIPS芯片采用大端,但可以在大小端之间切换
(4)在网络上传输的数据普遍采用的都是大端

大小端转换的代码
#define SWITCH16(n)			(((n & 0x00ff) << 8) | ((n & 0xff00) >> 8))
#define SWITCH32(n)			(((n & 0x000000ff) << 24) | ((n & 0xff000000) >> 24) | ((n & 0x00ff0000) >> 8) | ((n & 0x0000ff00) << 8))

对于一个字节的数据 不存在大小端问题 这里主要是16位数或者32位数在存储时高低位到底是低地址还是高地址 网络传输时到底是先传输高位还是地位

二 、GCC堆栈保护

Gcc编译器关于堆栈保护有如下的三种选项 默认堆栈保护是开启的 如果禁用堆栈保护可以加编译选项-fno-stack-protector
(1)-fstack-protector:
启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码
(2)-fstack-protector-all:
启用堆栈保护,为所有函数插入保护代码。
(3)-fno-stack-protector:
禁用堆栈保护。
如下的这段测试代码

#include <stdio.h>
#include <stdlib.h>


int main()
{
	int i=0;
	int attr[3]={0};

	for(;i<=3;i++)
	{
		attr[i]=0;
		printf("hello world...\n");
	}
	printf("exit...\n");
}

在linux系统上直接使用gcc test.c 命令编译执行 执行结果如下:
在这里插入图片描述

如果gcc 编译时去掉堆栈保护 加加上编译选项-fno-stack-protector
程序运行后发现会无限循环的打印hello world…

那么这里具体是什么原因呢?
由于我们的循环条件中i<3 错误的写成 了i<=3 当i=3时attr[3]=0 这个时候由于attr[3]数组访问 已经越界 此时实际是变量i的值变成了1 导致了无限循环。

那么为什么访问了越界的数组值 却实际是改了变量i的值呢?这里我们在做一个测试 对于如下的测试代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
        int i=0;
        int attr[3]={0};
        printf("i_addr=%d\n",&i);
        printf("attr[0]=%d\n",&attr[0]);
        printf("attr[1]=%d\n",&attr[1]);
        printf("attr[2]=%d\n",&attr[2]);
        printf("attr[3]=%d\n",&attr[3]);
        printf("exit...\n");
}

直接gcc test.c 编译运行结果如下:
在这里插入图片描述
从打印的地址来看 我们而已看到 main函数定义的变量attr[3]的地址和i的地址不是一个

如果去掉堆栈保护,即编译时加上编译选项-fno-stack-protector 在编译运行 结果如下:

在这里插入图片描述

我们发现 此时变量attr[3]的地址正好就是变量i的地址 因此我们越界访问变量attr[3]实际上就是更改了变量i的值导致程序陷入了死循环。
那么gcc编译器的堆栈保护又是什么原理呢?去掉堆栈保护后访问的越界元素的地址和加上堆栈保护后访问的越界元素的地址又不一样了?
这里网上查了下资料
对于越界访问的变量 编译器会放置一个保护变量值 如果该值被修改了 编译器就会抛出异常或错误。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值