日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下x86_64进程地址空间布局

發布時間:2025/3/15 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下x86_64进程地址空间布局 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在x86_64下和i386下是類似的,本文主要關注vm.legacy_va_layout以及kernel.randomize_va_space參數影響下的進程空間內存宏觀布局,以及vDSO和多線程下的堆和棧分布。


情形一:

  • vm_legacy_va_layout=1
  • kernel.randomize_va_space=0

此種情況下采用傳統內存布局方式,不開啟隨機化,程序的內存布局

可以看出: 代碼段:0x400000–> 數據段 堆:向上增長 2aaaaaaab000–> 棧:7ffffffde000<–7ffffffff000 系統調用:ffffffffff600000-ffffffffff601000 你可以試一下其他程序,在kernel.randomize_va_space=0時堆起點是不變的


情形二:

  • vm_legacy_va_layout=0
  • kernel.randomize_va_space=0

現在默認內存布局,不隨機化

可以看出: 代碼段:0x400000–> 數據段 堆:向下增長 <–7ffff7fff000 棧:7ffffffde000<–7ffffffff000 系統調用:ffffffffff600000-ffffffffff601000


情形三:

  • vm_legacy_va_layout=0
  • kernel.randomize_va_space=2 //ubuntu 14.04默認值 使用現在默認布局,隨機化

對比兩次啟動的cat程序,其內存布局堆的起點是變化的,這從一定程度上防止了緩沖區溢出攻擊。


情形四:

  • vm_legacy_va_layout=1
  • kernel.randomize_va_space=2 //ubuntu 14.04默認值 與情形三類似,不再贅述

vDSO

在前面談了兩個不同參數下的進程運行時內存空間宏觀的分布。也許你會注意到這樣一個細節,在每個進程的stack以上的地址中,有一段動態變化的映射地址段,比如下面這個進程,映射到vdso。 >?

如果我們用ldd看相應的程序,會發現vdso在磁盤上沒有對應的so文件。 不記得曾經在哪里看到大概這樣一個問題: > getpid,gettimeofday是不是系統調用?

其實這個問題的答案就和vDSO有關,雜x86_64和i386上,getpid是系統調用,而gettimeofday不是。

vDSO全稱是virtual dynamic shared object,是一種內核將一些本身應該是系統調用的直接映射到用戶空間,這樣對于一些使用比較頻繁的系統調用,直接在用戶空間調用可以節省開銷。如果想詳細了解,可以參考這篇文檔

下面我們用一段程序驗證下:

#include <stdio.h> #include <sys/time.h> #include <sys/syscall.h> #include <unistd.h>int main(int argc, char **argv) {struct timeval tv;int ret;if ((ret=gettimeofday(&tv, NULL))<0) {fprintf(stderr, "gettimeofday call failed\n");}else{fprintf(stdout, "seconds:%ld\n", (long int)tv.tv_sec);}fprintf(stdout, "pid:%d\n", (int)getpid());fprintf(stdout, "thread id:%d\n", (int)syscall(SYS_gettid));return 0; }

編譯為可執行文件后,我們可以用strace來驗證:

strace -o temp ./vdso grep getpid temp grep gettimeofday temp

多線程的堆棧

  • 三個線程的進程:

  • 主線程:

  • 子線程1:

  • 子線程2:

  • 測試代碼1:
#include <pthread.h> #include <unistd.h> #include <stdio.h>void *routine(void *args) {fprintf(stdout, "========\n");char arr[10000];fprintf(stdout, "temp var arr address in child thread : %p\n", arr);char arr1[10000];fprintf(stdout, "temp var arr1 address in child thread : %p\n", arr1);fprintf(stdout, "delta : %ld\n", arr1 - arr);for(;;) {sleep(5);} }int main(int argc, char *argv[]) {// argc 4// argv ?pthread_t pt; // 4pthread_t pt1; // 4int ret; // 4// pthread max stack size(can be changed): 0x800000 = 8M// char bigArr[0x800000 - 10000]; // SEGMENT FAULT//char arr1[144000];char arr1[144];arr1[0] = 'a';fprintf(stdout, "temp var arr1 address in main thread lower than 139 K : %p\n", arr1);//char arr2[100];char arr2[1];fprintf(stdout, "temp var arr2 address in main thread lower than 139 K : %p\n", arr2);fprintf(stdout, "delta : %ld\n", arr2 - arr1);//char arr3[100];char arr3[10];fprintf(stdout, "temp var arr3 address in main thread lower than 139 K : %p\n", arr3);fprintf(stdout, "delta : %ld\n", arr3 - arr2);ret = pthread_create(&pt, NULL, routine, NULL);ret = pthread_create(&pt1, NULL, routine, NULL);pthread_join(pt, NULL); pthread_join(pt1, NULL); return 0; }
  • 測試代碼2:打印內核棧地址
#include <linux/module.h> #include <linux/errno.h> #include <linux/sched.h> #include <asm/thread_info.h>static int test_param = 10; module_param(test_param, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(test_param, "a test parameter");static int print_all_processes_init(void) {struct task_struct *p;for_each_process(p) {if (p->pid == 1) {printk(KERN_INFO "stack : %p\n", p->stack);}};return 0; }static void print_all_processes_exit(void) {printk(KERN_INFO "unload module print_all_processes\n"); }module_init(print_all_processes_init); module_exit(print_all_processes_exit);MODULE_AUTHOR("FEILENGCUI"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("A MODULE PRINT ALL PROCESSES");
  • 對應init進程的內核棧stack起始地址

  • 用戶態線程棧在同一進程空間的堆起始部分分配,x86_64默認是8M,可以通過ulimit等方法設置
  • 用戶態線程棧的增長是從低的線性地址往高增長
  • 內核棧位于高地址
  • 主線程的棧(姑且稱為進程棧吧)行為比較怪異,后面會詳細分析glibc的ptmalloc下多線程程序malloc和線程棧的內存分配行為
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!

總結

以上是生活随笔為你收集整理的Linux下x86_64进程地址空间布局的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。