深入分析 dyld 的源码需要详细了解其内部结构和关键函数

296 阅读2分钟

深入分析 dyld 的源码需要详细了解其内部结构和关键函数。以下是一些关键部分的详细分析,结合了 dyld 的源码。

1. 加载可执行文件及其依赖库

详细分析

dyld 通过 _main 函数开始执行,该函数负责初始化环境并加载主可执行文件及其依赖库。

// dyld/src/dyld.cpp
void dyld::_main(const macho_header* mainExecutableMH, uintptr_t* mainExecutableSlide) {
    // 初始化环境
    initializeProcess();

    // 加载主可执行文件
    sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide);

    // 加载插入的库
    loadInsertedDylibs();

    // 加载依赖库
    link(sMainExecutable);
}

instantiateFromLoadedImage 函数负责创建 ImageLoader 对象,这是 dyld 中用于表示已加载图像的核心类。

// dyld/src/ImageLoader.cpp
ImageLoader* instantiateFromLoadedImage(const macho_header* mh, uintptr_t slide) {
    // 创建 ImageLoader 对象
    ImageLoader* image = ImageLoaderMachO::instantiateMainExecutable(mh, slide);
    return image;
}

2. 解析符号和重定位

详细分析

link 函数负责解析符号和重定位。它遍历所有已加载的图像,并调用它们的 link 方法。

// dyld/src/dyld.cpp
void dyld::link(ImageLoader* image) {
    // 解析符号并进行重定位
    image->link(context, preflightOnly, false);
}

ImageLoader 类的 link 方法负责解析符号和重定位。

// dyld/src/ImageLoader.cpp
void ImageLoader::link(const LinkContext& context, bool preflightOnly, bool neverUnload) {
    // 解析符号
    resolveSymbols(context);

    // 重定位
    applyFixUps(context);
}

3. 处理 dyld 插入库

详细分析

loadInsertedDylibs 函数负责加载通过 DYLD_INSERT_LIBRARIES 环境变量指定的库。

// dyld/src/dyld.cpp
void dyld::loadInsertedDylibs() {
    const char* const* dylibs = getenv("DYLD_INSERT_LIBRARIES");
    if (dylibs != NULL) {
        for (const char* const* dp = dylibs; *dp != NULL; ++dp) {
            loadDylib(*dp);
        }
    }
}

loadDylib 函数负责加载指定的动态库。

// dyld/src/dyld.cpp
void dyld::loadDylib(const char* path) {
    // 加载动态库
    ImageLoader* image = load(path);
    if (image != NULL) {
        addImage(image);
    }
}

4. 运行初始器(Initializers)

详细分析

runInitializers 函数负责运行所有已加载图像的初始器。

// dyld/src/dyld.cpp
void dyld::runInitializers(ImageLoader* image) {
    // 运行初始器
    image->runInitializers(context);
}

ImageLoader 类的 runInitializers 方法负责运行初始器。

// dyld/src/ImageLoader.cpp
void ImageLoader::runInitializers(const LinkContext& context) {
    // 运行初始器
    processInitializers(context);
}

5. 处理 @rpath, @loader_path, @executable_path

详细分析

getRealPath 函数负责解析特殊路径符号。

// dyld/src/ImageLoader.cpp
const char* ImageLoader::getRealPath(const char* path) {
    if (strncmp(path, "@rpath", 6) == 0) {
        // 处理 @rpath
        return resolveRPath(path);
    } else if (strncmp(path, "@loader_path", 12) == 0) {
        // 处理 @loader_path
        return resolveLoaderPath(path);
    } else if (strncmp(path, "@executable_path", 16) == 0) {
        // 处理 @executable_path
        return resolveExecutablePath(path);
    }
    return path;
}

总结

dyld 的源码展示了其复杂的内部结构和关键函数。通过深入分析这些函数,我们可以更好地理解 dyld 是如何加载可执行文件和共享库、解析符号、重定位地址、运行初始器以及处理特殊路径符号的。这些分析有助于我们更好地理解动态链接器的工作原理,并在需要时进行调试和优化。