Reputation: 201
When I execute a 64-bit process and look at /proc/[pid]/maps
, the layout show that the shared libraries and stack section are in a larger address; such as the following:
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]
Can I limit these sections to less 4G space and it must still be a 64-bit process rather than compile it into a 32-bit process?
Upvotes: 3
Views: 1353
Reputation: 239041
Based on your comment:
I am using llvm jit and forcing it to generate the x86 code in a 64-bit process. When I generate code for a "printf" instruction, it will call the function in libc; but the size of register is become 32-bit, I can't reach to address (The libc address is in 7fffxxxxxxxx.)
...merely limiting libraries to 32 bit addresses is entirely insufficient. For one thing, the calling convention is different in 64 bit mode - the 64 bit printf()
expects its first parameter in %rdi
, but the 32 bit code will instead push it on the stack.
You will need to have the generated code call a printf()
wrapper that sets up the parameters correctly for the call to the real printf()
. You can put that wrapper in a MAP_32BIT
region.
Upvotes: 0
Reputation: 3008
Seeing I was voted down I went and re-corrected the answer.
For Microsoft Visual Studio C++ if the compiler is a 32bit compiler, the /LARGEADDRESSAWARE flag sets the virtual address space from 2gb to 3gb this is only when running on a 32bit OS.
When running the same 32bit program on a 64bit os, the application will be given access to the full 4gb of virtual address space. For 64bit compilers the /LARGEADDRESSAWARE flag is enabled by default.
Seeing this question is for GCC I guess its not important for your problem.
Upvotes: -1
Reputation: 104050
While the prelink(8)
tool and concept are widely detested (and probably not shipped on your distribution), you may be able to use it to link libraries into a binary into low memory:
-r --reloc-only=ADDRESS
Instead of prelinking, just relink given shared libraries
to the specified base address.
Since the address that libraries will be mapped into the process is determined by ld(1)
, you might be able to modify your Makefile
to invoke ld
with different --section-start
values:
--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
I moved the text and bss segments down to lower addresses:
$ 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
...
If you can move all the sections provided in the executable with --section-start
and move the libraries down with prelink(8)
, you might be able to get all the code loaded below 4 gigabytes.
Upvotes: 3
Reputation: 24867
I don't know any general answer to this, but if you patched libc and the kernel, you could modify them to never create any address higher than 4G. Then your user mode code would not have to changed at all, any generated address through for example malloc() would never be above 4G.
It may also be most convenient if the machine you ran the kernel also has at most 4G combined swap and physical memory.
One thing to try, is to turn off overcommit. According to this page, if you set overcommit to "2" (off), and use say, 512 megabyte physical memory (including swap) then your address space should never grow outside of what a 32 bit address can hold. There may also be some kind of offset added to the 64 bit addresses, but in that case you should be able to find it and remove it.
Yet another idea is very hackish, but might work. Allocate shared memory from a 32 bit process and use this memory in your 64 bit process.
Upvotes: 0