简体   繁体   English

如何获得__NSAutoreleaseNoPool地址?

[英]how can I get the `__NSAutoreleaseNoPool` address?

I tried with 我尝试过

extern void __NSAutoreleaseNoPool(void* obj);

but that results in an unresolved symbol when linking (not sure what Framework it needs, though). 但这会导致链接时出现无法解析的符号(尽管不确定它需要什么框架)。

I also tried 我也试过

dlsym(RTLD_DEFAULT, "__NSAutoreleaseNoPool")

but that just gives be NULL . 但这只是给NULL

And I tried with _dyld_lookup_and_bind and NSLookupSymbolInImage but they also don't work. 我尝试了_dyld_lookup_and_bindNSLookupSymbolInImage但它们也无法正常工作。

dsymutil and nm both find the symbol, though: dsymutilnm都找到该符号,但是:

$ dsymutil -s --arch=x86_64 
----------------------------------------------------------------------
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
----------------------------------------------------------------------
Symbol table for: '/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation' (x86_64)
----------------------------------------------------------------------
Index    n_strx   n_type             n_sect n_desc n_value
======== -------- ------------------ ------ ------ ----------------
[     0] 00010795 1e (PEXT SECT    ) 01     0000   0000000000000000 '__mh_dylib_header'
[     1] 000107a7 0e (     SECT    ) 01     0000   0000000000001c20 '+[NSObject(NSObject) load]'
[     2] 000107c2 0e (     SECT    ) 01     0000   0000000000002630 '___exceptionInit'
[     3] 000107d3 0e (     SECT    ) 01     0000   00000000000029e0 '___CFgetenv'
[     4] 000107df 0e (     SECT    ) 01     0000   0000000000002a50 '___CFBaseInitialize'
...
[  1923] 0001e820 0e (     SECT    ) 01     0000   000000000010ad30 '___NSAutoreleaseNoPool'
...

$ nm -arch x86_64 /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
...
000000000010ad30 t ___NSAutoreleaseNoPool
...

(That is on MacOSX 10.6. On later MacOSX versions, the symbol really does not seem to exists, at least I cannot find any ref via grep in /usr/lib and /System/Library/Frameworks and also LLDB does not find it. Probably it was removed somehow with ARC.) (即在MacOSX 10.6上。在更高版本的MacOSX上,该符号似乎并不存在,至少我无法通过grep/usr/lib/System/Library/Frameworks找到任何引用,并且LLDB也找不到它。可能已通过ARC将其删除。)

So, how can I get that address in my code? 那么,如何在代码中获取该地址?

(Related questions: here and here ) (相关问题: 这里这里

(My motivation to do this is here .) (我的动机是在这里 。)

This works: 这有效:

#include <dlfcn.h>
#include <stdio.h>
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#include <mach-o/nlist.h>
#include <string.h>
#include <assert.h>

// Adapted from:
// https://github.com/0xced/iOS-Artwork-Extractor/blob/master/Classes/FindSymbol.c
// Adapted from MoreAddrToSym / GetFunctionName()
// http://www.opensource.apple.com/source/openmpi/openmpi-8/openmpi/opal/mca/backtrace/darwin/MoreBacktrace/MoreDebugging/MoreAddrToSym.c
void *FindSymbol(const struct mach_header *img, const char *symbol)
{
    if ((img == NULL) || (symbol == NULL))
        return NULL;

    // only 64bit supported
#if defined (__LP64__)

    if(img->magic != MH_MAGIC_64)
        // we currently only support Intel 64bit
        return NULL;

    struct mach_header_64 *image = (struct mach_header_64*) img;

    struct segment_command_64 *seg_linkedit = NULL;
    struct segment_command_64 *seg_text = NULL;
    struct symtab_command *symtab = NULL;
    unsigned int index;

    struct load_command *cmd = (struct load_command*)(image + 1);

    for (index = 0; index < image->ncmds; index += 1, cmd = (struct load_command*)((char*)cmd + cmd->cmdsize))
    {
        switch(cmd->cmd)
        {
            case LC_SEGMENT_64: {
                struct segment_command_64* segcmd = (struct segment_command_64*)cmd;
                if (!strcmp(segcmd->segname, SEG_TEXT))
                    seg_text = segcmd;
                else if (!strcmp(segcmd->segname, SEG_LINKEDIT))
                    seg_linkedit = segcmd;
                break;
            }

            case LC_SYMTAB:
                symtab = (struct symtab_command*)cmd;
                break;

            default:
                break;
        }
    }

    if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
        return NULL;

    unsigned long vm_slide = (unsigned long)image - (unsigned long)seg_text->vmaddr;
    unsigned long file_slide = ((unsigned long)seg_linkedit->vmaddr - (unsigned long)seg_text->vmaddr) - seg_linkedit->fileoff;
    struct nlist_64 *symbase = (struct nlist_64*)((unsigned long)image + (symtab->symoff + file_slide));
    char *strings = (char*)((unsigned long)image + (symtab->stroff + file_slide));
    struct nlist_64 *sym;

    for (index = 0, sym = symbase; index < symtab->nsyms; index += 1, sym += 1)
    {
        if (sym->n_un.n_strx != 0 && !strcmp(symbol, strings + sym->n_un.n_strx))
        {
            unsigned long address = vm_slide + sym->n_value;
            if (sym->n_desc & N_ARM_THUMB_DEF)
                return (void*)(address | 1);
            else
                return (void*)(address);
        }
    }   
#endif

    return NULL;
}

typedef void (*NSAutoreleaseNoPoolFunc) (void* obj);

void getNSAutoreleaseNoPool() { 
    const struct mach_header* img = NSAddImage("/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", NSADDIMAGE_OPTION_NONE);
    NSAutoreleaseNoPoolFunc f = (NSAutoreleaseNoPoolFunc) FindSymbol((struct mach_header*)img, "___NSAutoreleaseNoPool");

    printf("func: %p\n", f);

    if(f) {
        NSObject* foo = [[NSObject alloc] init];
        f(foo);
    }
}

It gets the same function pointer as within GDB. 它获得与GDB相同的功能指针。

Note that you wont see the common NSAutoreleaseNoPool log: 请注意,您不会看到常见的NSAutoreleaseNoPool日志:

2014-02-18 14:46:26.583 a.out[24989:a0b] *** __NSAutoreleaseNoPool(): Object 0x7fff71154190 of class NSCFString autoreleased with no pool in place - just leaking

The standard backtrace, when that happens, is this: 当发生这种情况时,标准回溯是这样的:

(gdb) bt
#0  0x00007fff8724bd34 in __NSAutoreleaseNoPool ()
#1  0x00007fff87196e79 in _CFAutoreleasePoolAddObject ()
#2  0x00007fff87196be6 in -[NSObject(NSObject) autorelease] ()

The actual NSLog call is done in _CFAutoreleasePoolAddObject . 实际的NSLog调用是在_CFAutoreleasePoolAddObject完成的。

A note about __NSAutoreleaseNoPool , from Foundation/NSDebug.h : 来自Foundation/NSDebug.h有关__NSAutoreleaseNoPool Foundation/NSDebug.h

/****************   Autorelease pool debugging  ****************/

// Functions used as interesting breakpoints in a debugger
// void __NSAutoreleaseNoPool(void *object);
    // Called to log the "Object X of class Y autoreleased with no
    // pool in place - just leaking" message.  If an environment
    // variable named "NSAutoreleaseHaltOnNoPool" is set with string
    // value "YES", the function will automatically break in the
    // debugger (or terminate the process).

// void __NSAutoreleaseFreedObject(void *freedObject);
    // Called when a previously freed object would be released
    // by an autorelease pool.  If an environment variable named
    // "NSAutoreleaseHaltOnFreedObject" is set with string value
    // "YES", the function will automatically break in the debugger
    // (or terminate the process).

So, if you want to debug such cases, either start up GDB and issue b __NSAutoreleaseNoPool to setup the breakpoint on this function. 因此,如果要调试这种情况,请启动GDB并发出b __NSAutoreleaseNoPool以在此函数上设置断点。 Or do an export NSAutoreleaseHaltOnNoPool=1 in your shell. 或者在您的shell中执行export NSAutoreleaseHaltOnNoPool=1

__NSAutoreleaseNoPool is pretty simple: __NSAutoreleaseNoPool非常简单:

(gdb) disassemble 
Dump of assembler code for function __NSAutoreleaseNoPool:
0x00007fff8724bd30 <__NSAutoreleaseNoPool+0>:   push   %rbp
0x00007fff8724bd31 <__NSAutoreleaseNoPool+1>:   mov    %rsp,%rbp
0x00007fff8724bd34 <__NSAutoreleaseNoPool+4>:   nop    
0x00007fff8724bd35 <__NSAutoreleaseNoPool+5>:   nopl   0x0(%rax)
0x00007fff8724bd39 <__NSAutoreleaseNoPool+9>:   lea    0x2ced8(%rip),%rdi        # 0x7fff87278c18 <__PRETTY_FUNCTION__.27904+480>
0x00007fff8724bd40 <__NSAutoreleaseNoPool+16>:  callq  0x7fff871439e0 <__CFgetenv>
0x00007fff8724bd45 <__NSAutoreleaseNoPool+21>:  test   %rax,%rax
0x00007fff8724bd48 <__NSAutoreleaseNoPool+24>:  je     0x7fff8724bd55 <__NSAutoreleaseNoPool+37>
0x00007fff8724bd4a <__NSAutoreleaseNoPool+26>:  movzbl (%rax),%eax
0x00007fff8724bd4d <__NSAutoreleaseNoPool+29>:  cmp    $0x59,%al
0x00007fff8724bd4f <__NSAutoreleaseNoPool+31>:  je     0x7fff8724bd60 <__NSAutoreleaseNoPool+48>
0x00007fff8724bd51 <__NSAutoreleaseNoPool+33>:  cmp    $0x79,%al
0x00007fff8724bd53 <__NSAutoreleaseNoPool+35>:  je     0x7fff8724bd60 <__NSAutoreleaseNoPool+48>
0x00007fff8724bd55 <__NSAutoreleaseNoPool+37>:  leaveq 
0x00007fff8724bd56 <__NSAutoreleaseNoPool+38>:  retq   
0x00007fff8724bd57 <__NSAutoreleaseNoPool+39>:  nopw   0x0(%rax,%rax,1)
0x00007fff8724bd60 <__NSAutoreleaseNoPool+48>:  int3   
0x00007fff8724bd61 <__NSAutoreleaseNoPool+49>:  callq  0x7fff872609c2 <dyld_stub_getpid>
0x00007fff8724bd66 <__NSAutoreleaseNoPool+54>:  mov    %eax,%edi
0x00007fff8724bd68 <__NSAutoreleaseNoPool+56>:  mov    $0x9,%esi
0x00007fff8724bd6d <__NSAutoreleaseNoPool+61>:  leaveq 
0x00007fff8724bd6e <__NSAutoreleaseNoPool+62>:  jmpq   0x7fff87260a16 <dyld_stub_kill>
0x00007fff8724bd73 <__NSAutoreleaseNoPool+67>:  nopw   0x0(%rax,%rax,1)
0x00007fff8724bd79 <__NSAutoreleaseNoPool+73>:  nopl   0x0(%rax)
End of assembler dump.

For a practical example, see demo_NSAutoreleaseNoPool.mm . 有关实际示例,请参见demo_NSAutoreleaseNoPool.mm

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM