What is the valid address space for the user process? (OS X and Linux)

The mmap system call documentation indicates that the function will fail if:

MAP_FIXED was specified, and the addr argument was not page aligned or partially needed address space from the actual address space for the user process.

I cannot find the documentation anywhere, saying what will be a valid address for matching. (I'm interested in doing this on OS X and Linux, ideally the same address will be valid for both ...).

+4
source share
2 answers

The Linux kernel reserves a portion of the virtual address space for itself, where the user space (almost) has no access and cannot display anything. You are looking for what is called user-space / kernel separation.

The i386 arch uses 3G / 1G by default - user space receives less than 3 GB of virtual address space, the kernel receives the top 1 GB, in addition, there are 2G / 2G and 1G / 3G:

 config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G default 0x78000000 if VMSPLIT_2G_OPT default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 

On x86_64, user space lives in the lower half (currently) of the 48-bit virtual address space:

 /* * User space process size. 47bits minus one guard page. */ #define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE) 
+7
source

It depends on a number of factors, many of which are not under your control. As Adobrian mentioned, depending on the OS, you have various fixed upper limits, beyond which lies the kernel code and data. Usually this upper limit is at least 2 GB on 32-bit OS; some operating systems provide additional address space. 64-bit operating systems usually provide an upper limit, controlled by the number of virtual address bits supported by your CPU (usually at least 40 bits of address space). However, there are other factors that you cannot control:

  • In the latest version of Linux, the mmap mapping below the address configured in /proc/sys/vm/mmap_min_addr will be rejected.
  • You cannot create mappings that overlap with any existing mappings. Since the dynamic linker is free to display anywhere that does not match your executable fixed partitions, this means that any address could potentially be denied.
  • The kernel may enter other optional mappings, such as a system call .
  • malloc can execute mmaps on their own, which fit in a slightly arbitrary arrangement

Thus, there is no way to ensure that MAP_FIXED is successful, and therefore should usually be avoided.

The only place I've seen where MAP_FIXED needed is an autorun start code that reserves (using MAP_FIXED ) all addresses above 2G to avoid confusing Windows code that does not assume that mappings will never display with a negative address. This, of course, is a highly specialized use of the flag.

If you are trying to do this in order to avoid having to deal with offsets in shared memory, one option would be to convert pointers to a class to automatically handle offsets:

 template<typename T> class offset_pointer { private: ptrdiff_t offset; public: typedef T value_type, *ptr_type; typedef const T const_type, *const_ptr_type; offset_ptr(T *p) { set(p); } offset_ptr() { set(NULL); } void set(T *p) { if (p == NULL) offset = 1; else offset = (char *)p - (char *)this; } T *get() { if (offset == 1) return NULL; return (T*)( (char *)this + offset ); } const T *get() const { return const_cast<offset_pointer>(this)->get(); } T &operator*() { return *get(); } const T &operator*() const { return *get(); } T *operator->() { return get(); } const T *operator->() const { return get(); } operator T*() { return get(); } operator const T*() const { return get(); } offset_pointer operator=(T *p) { set(p); return *this; } offset_pointer operator=(const offset_pointer &other) { offset = other.offset; return *this; } }; 

Note. This is untested code, but should give you the basic idea.

+1
source

Source: https://habr.com/ru/post/1342410/


All Articles