美文网首页iOS开发 技术集锦
线程、函数的调用地址

线程、函数的调用地址

作者: stonly916 | 来源:发表于2018-12-18 14:09 被阅读49次

线程的调用就会有函数的调用,就会把调用地址压入栈中,所以就可以从栈中获取调用地址。

通过[NSThread callStackReturnAddresses],可以获取线程的调用地址:

#include <dlfcn.h>

    NSArray *address = [NSThread callStackReturnAddresses];
    Dl_info info = {0};
    
    dladdr((void *)[address[0] longLongValue], &info);
    printf("address-0 name:%s  adress:%p  nearAdress:%p\n", info.dli_fname, info.dli_fbase, info.dli_saddr);
    dladdr((void *)[address[1] longLongValue], &info);
    printf("address-1 name:%s  adress:%p  nearAdress:%p\n", info.dli_fname, info.dli_fbase, info.dli_saddr);
  ......

address 表示线程被压入栈中的地址的数组,
address[0]:表示最顶层的线程调用地址,就是当前执行地点的函数的初始地址,这里
info.dli_fbase表示当前执行文件的基地址,
info.dli_saddr表示当前执行函数的函数地址。

例如:

void otherFunc() {
    NSArray *address = [NSThread callStackReturnAddresses];
    Dl_info info = {0};
    
    dladdr((void *)[address[0] longLongValue], &info);
    printf("address-0 name:%s  adress:%p  nearAdress:%p\n", info.dli_fname, info.dli_fbase, info.dli_saddr);
    dladdr((void *)[address[1] longLongValue], &info);
    printf("address-1 name:%s  adress:%p  nearAdress:%p\n", info.dli_fname, info.dli_fbase, info.dli_saddr);
    dladdr((void *)[address[2] longLongValue], &info);
    printf("address-2 name:%s  adress:%p  nearAdress:%p\n", info.dli_fname, info.dli_fbase, info.dli_saddr);
    if (dladdr((void *)[address[3] longLongValue], &info) != 0) {
        printf("address-3 name:%s  adress:%p  nearAdress:%p\n", info.dli_fname, info.dli_fbase, info.dli_saddr);
    }
}
NSString * getSomeFunc()
{
    otherFunc();
    NSLog(@"getSomeFunc");
    return @"12";
}
- (void)viewDidLoad {
    [super viewDidLoad];
    getSomeFunc();
}

控制台输出:

po (void *)getSomeFunc
0x0000000103ebdeb0

address-0 name:/Users/.../Library/Developer/CoreSimulator/Devices/30C9CE64-9A7C-47D6-BFBC-8C86195F9CAA/data/Containers/Bundle/Application/AC3A1321-292A-4212-8AC5-0EBEBE8A53C7/DrawSomething.app/DrawSomething  adress:0x103ebb000  nearAdress:0x103ebdc70
address-1 name:/Users/.../Library/Developer/CoreSimulator/Devices/30C9CE64-9A7C-47D6-BFBC-8C86195F9CAA/data/Containers/Bundle/Application/AC3A1321-292A-4212-8AC5-0EBEBE8A53C7/DrawSomething.app/DrawSomething  adress:0x103ebb000  nearAdress:0x103ebdeb0
address-2 name:/Users/.../Library/Developer/CoreSimulator/Devices/30C9CE64-9A7C-47D6-BFBC-8C86195F9CAA/data/Containers/Bundle/Application/AC3A1321-292A-4212-8AC5-0EBEBE8A53C7/DrawSomething.app/DrawSomething  adress:0x103ebb000  nearAdress:0x103ebe460
address-3 name:/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 10.0.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/UIKit.framework/UIKit  adress:0x105cbb000  nearAdress:0x105e83b83
2018-12-18 13:45:45.293 DrawSomething[2432:113183] getSomeFunc

上面的输出很清楚的表明了:
0x103ebb000执行文件DrawSomething的基地址,
0x103ebdc70函数void otherFunc()的函数地址,
0x103ebdeb0函数NSString * getSomeFunc()的函数地址,
0x103ebe460方法(本质还是函数)- (void)viewDidLoad的函数地址,
0x105e83b83UIKit调用viewDidLoad的调用地址。

如果一个执行文件未发生改变,那么其中的函数所对应的偏移地址是不变的,那么就可以根据 偏移地址 + 基地址 来获取函数调用地址,从而调用函数。

    long long funcBasePoint = (long long)((void *)getSomeFunc);
    NSArray *address = [NSThread callStackReturnAddresses];
    Dl_info info = {0};
    dladdr((void *)[address[0] longLongValue], &info);
    long long basePoint = (long long)(info.dli_fbase);
    long offsetPoint = funcBasePoint - basePoint;
    
    void* addr = (void*)(offsetPoint + basePoint);
    ((void(*)(void))addr)();

当你知道别人执行文件的某个函数的偏移地址和基地址,你就可以调用别人的函数了。

相关文章

  • 线程、函数的调用地址

    线程的调用就会有函数的调用,就会把调用地址压入栈中,所以就可以从栈中获取调用地址。 通过[NSThread cal...

  • 多线程 Nsthread GCD 和 Nsopration 的

    一 pthread : /* 参数: 1.线程代号的地址 2.线程的属性 3.调用函数的指针 4.传递给函数的参...

  • 打印函数调用堆栈

    相关函数签名 backtrace():栈回溯,保存各个栈帧的地址。该函数用于获取当前线程的函数调用堆栈,获取的信息...

  • 内联函数

    解决函数调用效率的问题:函数之间调用,是内存地址之间的调用,当函数调用完毕之后还会返回原来函数执行的地址。函数调用...

  • 堆栈

    栈区属于线程自己占有(在栈区,系统以栈的形式管理函数调用,临时数据,返回地址等信息,先进后出 当前调用的函数在栈顶...

  • 线程状态

    一、线程状态 1. new:新创建一个线程对象,还未调用start函数 2. Runnable:调用start函数...

  • 终止进程

    主线程的入口点函数返回 调用ExitProcess 调用TerminateProcess 进程中所有线程全部“自然...

  • Python基础学习9

    多线程编程知识点记录:1、单线程函数如何转换为多线程1)线程函数调用 2)线程类调用 问题解答1:老师,我想不明白...

  • goroutine访问宿主函数局部变量

    我们知道goroutine函数会在一个不同于当前调用者线程的环境中运行;那么当调用者线程结束,或者调用者函数返回之...

  • inline.内联函数

    引入内联函数是为了解决函数调用效率的问题由于函数之间的调用,会从一个内存地址调到另外一个内存地址,当函数调用完毕之...

网友评论

    本文标题:线程、函数的调用地址

    本文链接:https://www.haomeiwen.com/subject/lrjghqtx.html