Search code examples
macosmemorylldbvirtual-memory

LLDB and the memory addresses of library functions


I have a "Hello World" program to which I've attached lldb. I'm trying to answer a few questions for myself about the results I get when I try to get the address of library functions:

(lldb) image lookup -n printf
1 match found in /usr/lib/system/libsystem_c.dylib:
        Address: libsystem_c.dylib[0x000000000003f550] (libsystem_c.dylib.__TEXT.__text + 253892)
        Summary: libsystem_c.dylib`printf
(lldb) image lookup -n scanf
1 match found in /usr/lib/system/libsystem_c.dylib:
        Address: libsystem_c.dylib[0x000000000003fc69] (libsystem_c.dylib.__TEXT.__text + 255709)
        Summary: libsystem_c.dylib`scanf
(lldb) expr &printf
(int (*)(const char *__restrict, ...)) $2 = 0x00007fff6f8c5550 (libsystem_c.dylib`printf)
(lldb) expr &scanf
error: unsupported expression with unknown type

I have three questions here:

  1. What kind of address is 0x00007fff6f8c5550? I assume it is the function pointer to printf. Is this a virtual address that exists only in the mapped space of the current process? If yes, why does another program return the same address for printf?

  2. Assuming it's some global shared address that is the same for every process, would modifying the contents of the data at this address (which I haven't been able to do yet) create a copy of the modified memory page and will the address change? (i'm on Mac OS and I assume one process cannot change shared memory for another process)

  3. Why does expr &scanf not work, but expr &printf does?


Solution

    1. What kind of address is 0x00007fff6f8c5550? I assume it is the function pointer to printf.

    Yes, that's correct.

    Is this a virtual address that exists only in the mapped space of the current process?

    Well, yes and no. It is a virtual address specific to your process and you should not assume it's valid in another process. But:

    If yes, why does another program return the same address for printf?

    As an optimization, macOS uses a shared mapping for a lot of the system libraries. They are loaded once at boot and used by all processes. For a given boot, the address is constant across all such processes. However, the address is randomized each boot for security.

    1. Assuming it's some global shared address that is the same for every process, would modifying the contents of the data at this address (which I haven't been able to do yet) create a copy of the modified memory page and will the address change?

    Well, it is mapped copy-on-write. So, modifying it would create a copy. However, that wouldn't change its address. The OS would simply modify the mapping so that the memory around that address is private to your process.

    (i'm on Mac OS and I assume one process cannot change shared memory for another process)

    Well, processes can cooperate to have writable shared memory. But, in general, you're correct that security precautions prevent unwanted modifications to a process's memory.

    1. Why does expr &scanf not work, but expr &printf does?

    Your program (presumably) doesn't use scanf, so there's no debugging information regarding it. The main thing lldb is missing is the type of scanf. If you use a cast expression, it can work:

    (lldb) p scanf
    error: 'scanf' has unknown type; cast it to its declared type to use it
    (lldb) p &scanf
    error: unsupported expression with unknown type
    (lldb) p (int(*)(const char * __restrict, ...))scanf
    (int (*)(const char *__restrict, ...)) $3 = 0x00007fffd7e958d4 (libsystem_c.dylib`scanf)
    

    Conversely, it works for printf because your program does use it.