2014-02-18 4 views
1

Я попытался сКак я могу получить адрес `__NSAutoreleaseNoPool`?

extern void __NSAutoreleaseNoPool(void* obj); 

но приводит к неразрешенному символу при компоновке (не уверен, что основа для этого нужно, хотя).

Я также попытался

dlsym(RTLD_DEFAULT, "__NSAutoreleaseNoPool") 

, но это просто дает быть NULL.

И я пробовал с _dyld_lookup_and_bind и NSLookupSymbolInImage, но они также не работают.

dsymutil и nm как найти символ, хотя:.

$ 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 
... 

(То есть на MacOSX 10.6 На более поздних версий MacOSX, символ действительно, кажется, не существует, по крайней мере, я не могу найти какой-либо реф через grep в /usr/lib и /System/Library/Frameworks, а также LLDB не находит его. Вероятно, она была удалена как-то с ARC.)

Итак, как я могу получить этот адрес в моем коде?

(Связанные вопросы: here и here)

(Моя мотивация сделать это here.)

+0

Что вы хотите достичь? Зачем вам нужен адрес? – Volker

+0

@Volker: Просто попробуйте хакерство с mach_override. – Albert

+0

Попробуйте сделать одно подчеркивание; первый из них - cdecl name mangling. – hamstergene

ответ

2

Это работает:

#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); 
    } 
} 

Он получает тот же указатель на функцию, как в GDB.

Обратите внимание, что вы обыкновение видеть общий 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 

Стандарт трассировку, когда это произойдет, это:

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

Фактическое NSLog вызов делается в _CFAutoreleasePoolAddObject.

Примечание о __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). 

Итак, если вы хотите отлаживать такие случаи, как запустить GDB и вопрос b __NSAutoreleaseNoPool установить точку останова на эту функцию. Или сделайте export NSAutoreleaseHaltOnNoPool=1 в своей оболочке.

__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. 

Для практического примера см demo_NSAutoreleaseNoPool.mm.

Смежные вопросы