Using mmap() on OSX for a specific memory range?

Discussion in 'Mac Programming' started by blueshogun96, Dec 12, 2016.

  1. blueshogun96 macrumors regular

    blueshogun96

    Joined:
    Nov 24, 2012
    #1
    I remember asking a similar question once before, but resolved my previous issue. Now I have a different issue that I cannot seem to figure out.

    As a quick recap, I was asking about how to obtain the first 64mb of address space with in the 32-bit address space. At first it didn't work because I forgot to tell XCode I'm building an i386 app instead of x86_64. This is the code I was using to test it:

    Code:
    #include <sys/mman.h>
    #include <iostream>
    #include <stdio.h>
    
    namespace {
        void * const MEMORY_ADDRESS = reinterpret_cast<void *>(0x10000);
        size_t const MEMORY_SIZE = 64*1024*1024;
    }
    
    int main() {
        void * p = mmap(MEMORY_ADDRESS, MEMORY_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
        if (p != reinterpret_cast<void *>(-1)) {
            //std::cout << "Memory allocated " << std::endl;
            printf( "Memory allocated" );
            munmap(p, MEMORY_SIZE);
        } else {
            //std::cout << "Memory could not be allocated (error: " << errno << ")" << std::endl;
            printf( "Memory could not be allocated (error: %d)", errno );
        }
    }
    Now, the call to mmap() was successful, but it causes a crash soon after. The call to printf also crashes, same with std::cout. Even if I comment this out, the program will crash also. I'm not sure why. This code works without issues on Linux, but not for Mac. I've done a similar trick on Windows, but I had to explicitly force the .exe 's base address to 0x10000 and create a static array of 64mb.

    Why am I doing this? This is for an emulation experiment. In order for this to work, I need to have at least a few megabytes after 0x10000. No other base address will do as I am dealing with absolute memory address jumps most of the time.

    Is there a way to set/change the base address of the app in XCode? I looked through the options and didn't see any way to change this. Maybe that would help in case I am interfering with some delicate processes.

    Any ideas? Thanks.

    Shogun
     
  2. mfram, Dec 13, 2016
    Last edited: Dec 13, 2016

    mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #2
    You do realize that even if you map that address, it's a virtual address within your process's virtual address space? You aren't seeing physical memory. The memory you see will be totally dependent on how the loader and dynamic construct the address space for that program.

    I did try the program out though. The "FIXED" flag is the issue. After turning it off, I was getting these sample addresses:
    returns 0x10731b000
    returns 0x10e65c000
    returns 0x109d58000
     
  3. blueshogun96 thread starter macrumors regular

    blueshogun96

    Joined:
    Nov 24, 2012
    #3
    I believe the virtual address should be fine. As long as I can "jump" to it.

    Btw, the FIXED flag needs to be there in order to get that address. Looking at those addresses, they are above the 4GB address space. Did you build this in 32-bit (i386) mode? Because if you don't, the above program will always fail.

    Shogun.
     
  4. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #4
    Maybe your emulator should be doing the address translation. The program in the emulator would use "emulator addresses". Your program translates those addresses with an offset. Then you don't care in your program's address space the where buffer is mapped. That's probably the most portable way to go.
     
  5. Terminated macrumors newbie

    Joined:
    Mar 18, 2014
    #5
    Using MAP_FIXED on arbitrary locations may remove existing overlapping mappings without warning, so it's unsafe. It's also unsafe in Linux, but it may work depending on luck. To be able to use MAP_FIXED safely you first need to ensure that the memory range is not in use by anything else.

    On Xcode, the simplest solution I found when working on a similar problem was to change build settings by adding this to "Other linker flags":

    -pagezero_size 0x10000000 -segprot __PAGEZERO rwx rwx

    I tried your code with this option in 32-bit mode and it worked. Be aware, though, that this removes protection against null pointer accesses, although in my case I didn't care because I actually wanted the virtual machine to access address 0 and I had not the choice of using a proper virtualization library.

    I also played a little with the -segaddr linker option and __attribute__((section()), but the above solution ended working better.
     
  6. blueshogun96, Dec 29, 2016
    Last edited: Dec 29, 2016

    blueshogun96 thread starter macrumors regular

    blueshogun96

    Joined:
    Nov 24, 2012
    #6
    Ah, very interesting. I will give this a try and see if I can get that particular memory range. Although I don't need the entire 64mb, it would be helpful. So I need to actually take a look at the documentation of that so I know exactly what that does since I've never done this before. So, in my case, would I need to use 0x10000 and that would reserve pages at that particular address that I need?

    Since I do not have the option of a proper VM library myself due to my machines being too far outdated, this would help tremendously. So I'm going to experiment a bit and see if it works for me.

    Thanks,

    Shogun.

    EDIT: Tried your solution, and that stopped it from crashing. Thanks a million! So from here, I'll try some experimenting and keep your words of wisdom in mind. Let's see of my little experiment yields some fruit after all.
     

Share This Page