歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

Linux中為什麼要隨機函數棧的起始地址

1. 如前文(http://www.linuxidc.com/Linux/2011-08/41869.htm)所述,為了執行一個程序,首先do_execve建立數據結構,並將一些數據從用戶空間拷貝到內核空間,然後調用search_binary_handler加載可執行文件映像。

  1. int do_execve(char * filename,  
  2.         char __user *__user *argv,  
  3.         char __user *__user *envp,  
  4.         struct pt_regs * regs)  
2. search_binary_handler()尋找對應的handler。對於elf 文件,即是load_elf_binary。
  1. int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)  

3. load_elf_binary()讀取可執行文件頭文件信息,進行簡單的一致性檢測,分配用戶模式的頁表,設置棧的起始地址,加載可執行文件映像到內存;然後調用create_elf_tables(); 最後調用start_thread(),執行_start函數開始的代碼。
  1. static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)  

4. create_elf_tables()將參數指針,環境變量數組指針壓入用戶模式的棧。

  1. static int  
  2. create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,  
  3.                 unsigned long load_addr, unsigned long interp_load_addr)  
值得注意的是,create_elf_tables()很可能會在壓棧前調整棧指針。比如,在支持超線程的體系結構裡面,通過隨機化初始棧指針,可以減少進程間在L1上的競爭。如下所示,隨機化初始棧指針的頁內偏移量,並使得棧指針保持16字節對齊。
  1. unsigned long arch_align_stack(unsigned long sp)  
  2. {  
  3.        if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)  
  4.                 sp -= get_random_int() % 8192;  
  5.         return sp & ~0xf;  
  6. }  
為什麼針對頁內偏移呢?

在某些體系結構中,首先要完成從邏輯地址到物理地址的轉換,然後才能去cache中查找該物理地址是否已經在cache當中。這樣,cache命中的代價較高。一種常用的技巧是,在L1中,邏輯地址索引-物理地址比較(virtually indexed, physically tagged)[1]。思路是,利用邏輯地址與物理地址的頁內偏移一樣的特點,用頁內偏移進行索引,頁號通過TLB轉換成物理頁號進行tag比較。這樣,可以不經轉換,就先索引,從而加快速度。這樣,如果兩個邏輯地址的塊內偏移一樣,它們索引的cache行也就一樣,所以需要隨機化頁內偏移來減少L1的競爭。其缺點是,L1的set大小,不能超過頁的大小。換言之:

    L1的大小 <= 相聯度 * 塊的大小 * 頁的大小

5. start_thread(),執行_start函數開始的代碼
  1. void  
  2. start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)  
  3. {  
  4.         set_user_gs(regs, 0);  
  5.         regs->fs                = 0;  
  6.         set_fs(USER_DS);  
  7.         regs->ds                = __USER_DS;  
  8.         regs->es                = __USER_DS;  
  9.         regs->ss                = __USER_DS;  
  10.         regs->cs                = __USER_CS;  
  11.         regs->ip                = new_ip;  
  12.         regs->sp                = new_sp;  
  13.         /* 
  14.          * Free the old FP and other extended state 
  15.          */  
  16.         free_thread_xstate(current);  
  17. }  
參考:[1] Computer Architecture: A Quantitative Approach, Fourth Edition. Page 291-292.
Copyright © Linux教程網 All Rights Reserved