linux内核学习-内存-分析程序的内存地址分配

前言

学习过linux后,知道linux程序内存结构可以分成五个区块。分别是“代码段”,“数据段“,”BSS段”,堆(head)和栈(stack)。他们分别的功能是
代码段: 存放程序编译后的机器代码,它是一块只读区。

数据段: 数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配[1]的变量和全局变量。

BSS段[2]: BSS段包含了程序中未初始化的全局变量,在内存中 bss段全部置零。

堆(heap): 堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

栈: 栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
在这里插入图片描述
如下我们将使用程序的方法,更加感性的认识这些区块。

程序代码

代码大体思路如下,注意,以下打印的地址,不一定就是这个区块的首地址。
1.代码段:就是main函数的内存地址
2.数据段:打印某个有初始化全局变量的地址
3.BSS段:打印某个未初始化的全局变量地址
4.堆:打印某个动态创建的变量的地址
5.栈:打印某局部变量的变量地址。

程序代码如下:

#include<stdio.h>
#include<malloc.h>
#include<unistd.h>

int bss_var;
int data_var0=1;

int main(int argc,char **argv)
{
	printf("below are addresses of types of process's mem\n");
	printf("Text location:\n");
	printf("\tAddress of main(Code Segment):%p\n",main);
	printf("____________________________\n");

	printf("Data Location:\n");
	printf("\tAddress of data_var(Data Segment):%p\n",&data_var0);
	static int data_var1=4;
	printf("\tNew end of data_var(Data Segment):%p\n",&data_var1);
	printf("____________________________\n");
	
	printf("BSS Location:\n");
	printf("\tAddress of bss_var:%p\n",&bss_var);
	printf("____________________________\n");

	int stack_var0=2;
	printf("Stack Location:\n");
	printf("\tInitial end of stack:%p\n",&stack_var0);
	int stack_var1=3;
	printf("\tnew end of stack:%p\n",&stack_var1);
	printf("____________________________\n");

	char *b = sbrk((ptrdiff_t)0);
	printf("Heap Location:\n");
	printf("\tInitial end of heap:%p\n",b);
	brk(b+4);
	b=sbrk((ptrdiff_t)0);
	printf("\tNew end of heap:%p\n",b);

	return 0;
}

程序输出结果如下
在这里插入图片描述
多次运行程序,我们发现代码段,数据段,BSS段都的地址都是固定好的,但是堆和栈的地址是动态变化的。该怎么解释呢?
在这里插入图片描述

在linux中,用户程序使用的是虚拟地址。也就是说,也就是说程序的运行之前,很多地址已经是确定好的。按照道理堆栈段都是固定的,但是因为系统开启了安全机制,程序在运行的时候,把堆栈的起始地址随机分配了,这样可以增加缓冲区溢出攻击的难度。

原理
操作系统分配进程栈的起始地址:操作系统给进程栈分配的起始地址为STACK_TOP,这个值一般也为TASK_SIZE,即为用户空间的最大地址(在32位系统中,该值为3G),但是如果系统设置PF_RANDOMIZE标志,则操作系统会在进程启动后,随机设置栈的起始位置,即为:STACK_TOP - randomized_variable,所以每次看到main函数局部变量地址是不一样的

STACK_TOP的代码如下

代码:在内核2.6.32中,对应的方法:
static unsignedlong randomize_stack_top(unsigned long stack_top)
{
  unsignedint random_variable = 0;
  
  if((current->flags & PF_RANDOMIZE) &&
    !(current->personality & ADDR_NO_RANDOMIZE)) {
    random_variable = get_random_int() & STACK_RND_MASK;
    random_variable <<= PAGE_SHIFT;
  }
#ifdef CONFIG_STACK_GROWSUP
  returnPAGE_ALIGN(stack_top) + random_variable;
#else
  returnPAGE_ALIGN(stack_top) - random_variable;
#endif
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值