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.
source share