2011-03-22 77 views
2

當我執行64位進程並查看/proc/[pid]/maps時,佈局顯示共享庫和堆棧部分位於更大的地址中;如以下內容:如何將64位進程地址空間限制爲小於4G?

7ffff7ffc000-7ffff7ffd000 r--p 0001d000 08:03 16643  /lib/ld-2.11.2.so 
7ffff7ffd000-7ffff7ffe000 rw-p 0001e000 08:03 16643  /lib/ld-2.11.2.so 
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffea000-7ffffffff000 rw-p 00000000 00:00 0   [stack] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 

我可以限制這些部分,以較少4G空間,它仍然必須是一個64位的處理,而不是將其編譯成一個32位的程序?

+2

有什麼特別的原因嗎? – Gabe 2011-03-22 07:58:33

+1

如果我可能會問 - 爲什麼你不想訪問整個64位地址空間? – paulcam 2011-03-22 08:09:00

+0

@Gabe:我正在使用llvm jit並強制它在64位進程中生成x86代碼。當我爲「printf」指令生成代碼時,它將調用libc中的函數;但寄存器的大小變爲32位,我無法到達地址(libc地址在7fffxxxxxxxx中。) – 2011-03-22 08:16:08

回答

-1

看到我被拒絕了,我去了,並重新更正了答案。

對於Microsoft Visual Studio C++(如果編譯器是32位編譯器),/ LARGEADDRESSAWARE標誌將虛擬地址空間從2gb設置爲3gb,這僅在32位操作系統上運行時纔有效。

在64位操作系統上運行相同的32位程序時,應用程序將可以訪問全部4GB的虛擬地址空間。對於64位編譯器,默認情況下啓用/ LARGEADDRESSAWARE標誌。

看到這個問題是爲海灣合作委員會我猜它不是你的問題重要。

+0

可能是GCC,因爲她正在使用Linux。 – 2011-03-22 07:54:38

+0

是的,我使用gcc。 – 2011-03-22 08:02:46

+0

即使在Windows的問題涉及Linux的時候允許對Windows的無端討論,您關於Windows的事實全部都沒有了。/LARGEADDRESAWARE是32位可執行文件的PE標誌。它標誌着能夠處理內存地址的最高位設置爲> 2GB的可執行文件。對於在32位Windows下使用/ 3GB引導開關運行的可執行文件以及在WOW64下的32位可執行文件非常有用。 – 2011-03-22 08:10:26

0

我不知道任何一般的答案,但是如果你修補了libc和內核,你可以修改它們從不創建任何高於4G的地址。那麼你的用戶模式代碼根本就不需要改變,例如malloc()的任何生成地址都不會超過4G。

如果運行內核的機器最多也有4G組合交換和物理內存,那麼這也可能是最方便的。

有一點要嘗試,就是關閉overcommit。根據this page,如果將overcommit設置爲「2」(關閉),並且使用512字節物理內存(,包括交換),則您的地址空間不應超出32位地址所能容納的範圍。有可能是一種偏移添加到64位地址,但在這種情況下,你應該能夠找到它並將其刪除。

另一個想法是非常黑客,但可能工作。從32位進程分配共享內存,並在64位進程中使用該內存。

+0

機器中的物理內存量與'ld.so(8)'在庫中動態鏈接時分配的虛擬地址無關。 – sarnold 2011-03-22 08:08:32

+0

@sarnold,不,但它有助於避免內核分配超過可以用32位表示的情況。但是,謝謝,我添加了「和合並交換」。 – 2011-03-22 08:18:05

0

也許這是你在找什麼:

man setrlimit 
+1

「RLIMIT_AS」地址空間限制僅限制一個進程可能分配的頁數,而不是分配哪些地址。參見'mm/mmap.c'中的'may_expand_vm()'。 – sarnold 2011-03-22 08:40:26

2

雖然prelink(8)工具和概念被廣泛厭惡(也可能不是隨你的發行版),你可以用它來庫鏈接到二進制到低內存:

-r --reloc-only=ADDRESS 
    Instead of prelinking, just relink given shared libraries 
    to the specified base address. 

由於該庫將被映射到進程的地址是由ld(1)確定,你也許可以修改Makefile調用ld與不同--section-start值:

--section-start SECTION=ADDRESS 
          Set address of named section 
-Tbss ADDRESS    Set address of .bss section 
-Tdata ADDRESS    Set address of .data section 
-Ttext ADDRESS    Set address of .text section 
-Ttext-segment ADDRESS  Set address of text segment 

我感動的文字和BSS段下降到低位地址:

$ gcc -Wl,-Ttext-segment=0x200000 -Wl,-Tbss=0x400000 -o broken broken.c 
$ readelf -a broken 
ELF Header: 
    Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
    Class:        ELF64 
    Data:        2's complement, little endian 
    Version:       1 (current) 
    OS/ABI:       UNIX - System V 
    ABI Version:      0 
    Type:        EXEC (Executable file) 
    Machine:       Advanced Micro Devices X86-64 
    Version:       0x1 
    Entry point address:    0x200450 
... 

如果你可以移動與--section-start可執行文件所提供的所有部分和移動圖書館下來prelink(8) ,您可能可以將所有代碼加載到4千兆字節以下。基於您的評論

+0

謝謝,這對我很好。但我仍然知道如何將共享庫(libc)鏈接到4G以下。我不知道如何使用-r選項。 – 2011-03-22 11:57:34

0

我使用LLVM JIT和迫使它 生成一個64位 過程中的x86代碼。當我爲 「printf」指令生成代碼時,它將調用libc中的 函數;但 寄存器的大小成爲32位,我不能 到達地址(libc的地址是在7fffxxxxxxxx 。)

...僅僅限制庫32位地址是完全不夠的。首先,64位模式下的調用約定是不同的 - 64位printf()需要%rdi中的第一個參數,但是32位代碼會將其推入堆棧。

您需要讓生成的代碼調用printf()包裝器,該包裝器正確設置了對真實printf()的調用的參數。您可以將該包裝器放入MAP_32BIT區域。

+0

如果我切換回兼容模式,調用約定是否會更改爲通過堆棧? – 2011-03-23 11:16:06

+0

@ Hsaio-Hui Chiu:否 - 圖書館代碼預期的調用約定,其中'printf'所在的地方是代碼的「烘焙」。改變CPU模式不會改變 - 實際上,64位庫代碼甚至不會在兼容模式下運行,因爲它充滿了在該模式下無效的指令序列。 – caf 2011-03-23 11:21:23

相關問題