美文网首页
iOS 寄存器编程引起的编译问题

iOS 寄存器编程引起的编译问题

作者: 算命的李老师 | 来源:发表于2021-06-21 14:49 被阅读0次

    一、寄存器编程代码

    1.实例

    在某些组件运用到了寄存器相关编程,目的是为了调出当前运行堆栈,部分应用代码如下:

    uintptr_t xol_mach_linkRegister(mcontext_t const machineContext){
    #if defined(__i386__) || defined(__x86_64__)
        return 0;
    #endif
    #if defined(__arm64__) || defined(__arm__)
        return machineContext->__ss.__lr;
    #endif
        return 0;
    }
    

    直接拿到 __ss 对应结构体看到 (以手机真机运行环境举例)

    _STRUCT_MCONTEXT64
    {
        _STRUCT_ARM_EXCEPTION_STATE64   __es;
        _STRUCT_ARM_THREAD_STATE64      __ss;
        _STRUCT_ARM_NEON_STATE64        __ns;
    };
    

    打开 _STRUCT_ARM_THREAD_STATE64 看到

    #define _STRUCT_ARM_THREAD_STATE64 struct __darwin_arm_thread_state64
    _STRUCT_ARM_THREAD_STATE64
    {
        __uint64_t __x[29]; /* General purpose registers x0-x28 */
        __uint64_t __fp;    /* Frame pointer x29 */
        __uint64_t __lr;    /* Link register x30 */
        __uint64_t __sp;    /* Stack pointer x31 */
        __uint64_t __pc;    /* Program counter */
        __uint32_t __cpsr;  /* Current program status register */
        __uint32_t __pad;   /* Same size for 32-bit or 64-bit clients */
    };
    

    项目里用到的属性有

        __uint64_t __fp;    /* Frame pointer x29 */
        __uint64_t __lr;    /* Link register x30 */
        __uint64_t __sp;    /* Stack pointer x31 */
        __uint64_t __pc;    /* Program counter */
    
    2. 寄存器对应设备:

    解释一下几个宏:
    i386 & x86 : 电脑模拟器
    __arm64__ : 现有的终端设备 (iPhone 12等)
    __arm__:包含armv7,armv7s,(iphone4,ipad2等)

    本组件不支持armv7与模拟器环境,但是由于是平台化app,各团队能修改的权限有限,如果主工程支持armv7,那么就要支持对应的打包环境。

    二、打包之路

    1.发布组件

    pod lib lint 不通过

    不同编译环境下的不同头文件路径:

    由于对不同编译环境的支持会引用到不同的宏,如:
    arm

    //文件路径 iOS 14.4 -> user/include/i386/_mcontext.h
    _STRUCT_MCONTEXT64
    {
        _STRUCT_ARM_EXCEPTION_STATE64   __es;
        _STRUCT_ARM_THREAD_STATE64      __ss;
        _STRUCT_ARM_NEON_STATE64        __ns;
    };
    

    i386

    //文件路径 Simulator iOS 14.4 -> user/include/i386/_mcontext.h
    _STRUCT_MCONTEXT32
    {
        _STRUCT_X86_EXCEPTION_STATE32   __es;
        _STRUCT_X86_THREAD_STATE32      __ss;
        _STRUCT_X86_FLOAT_STATE32       __fs;
    };
    

    对应的 __ss能指向的寄存器名称也不一样

    //文件路径 iOS 14.4 -> user/include/mach/arm/_structs.h
    // arm64
    _STRUCT_ARM_THREAD_STATE64
    {
        __uint64_t __x[29]; /* General purpose registers x0-x28 */
        __uint64_t __fp;    /* Frame pointer x29 */
        __uint64_t __lr;    /* Link register x30 */
        __uint64_t __sp;    /* Stack pointer x31 */
        __uint64_t __pc;    /* Program counter */
        __uint32_t __cpsr;  /* Current program status register */
        __uint32_t __pad;   /* Same size for 32-bit or 64-bit clients */
    };
    
    // i386
    //文件路径 Simulator iOS 14.4 -> user/include/mach/i386/_structs.h
    _STRUCT_X86_THREAD_STATE32
    {
        unsigned int    __eax;
        unsigned int    __ebx;
        unsigned int    __ecx;
        unsigned int    __edx;
        unsigned int    __edi;
        unsigned int    __esi;
        unsigned int    __ebp;
        unsigned int    __esp;
        unsigned int    __ss;
        unsigned int    __eflags;
        unsigned int    __eip;
        unsigned int    __cs;
        unsigned int    __ds;
        unsigned int    __es;
        unsigned int    __fs;
        unsigned int    __gs;
    };
    

    所以项目里代码写法:

    #if defined(__i386__) || defined(__x86_64__)
        return 0;
    #endif
    #if defined(__arm64__) || defined(__arm__)
        return machineContext->__ss.__pc;
    #endif
    
    报错:pod lib lint

    pod lib lint 时模拟器无法找到__arm64__环境

    解决方案:在podspec文件加上
    s.libraries = 'stdc++'
    

    2.打包framework

    pod 成功后,由于是平台化开发,所以主模块需要打包framework,主模块又引入了当前组件,当前组件引起报错

    报错: 平台framework打包报错

    error: no member named '__pc' in 'struct __darwin_arm_thread_state64' error: no member named '__lr' in 'struct __darwin_arm_thread_state64' error: no member named '__fp' in 'struct __darwin_arm_thread_state64' error: no member named '__sp' in 'struct __darwin_arm_thread_state64'

    原因:虽然开发过程中编译和运行没有问题,但是,jenkins打包环境下__darwin_arm_thread_state64环境下找不到__ss.__pc这种指定
    ,因为打包服务器集成了armv7armv7s等不同指令集架构

    解决方案:
    通过查看源码发现了这些宏

    //文件路径 iOS 14.4 -> user/include/mach/arm/_structs.h
    #define __darwin_arm_thread_state64_get_pc(ts) \
        ((ts).__pc)
    #define __darwin_arm_thread_state64_get_lr(ts) \
        ((ts).__lr)
    #define __darwin_arm_thread_state64_get_sp(ts) \
        ((ts).__sp)
    #define __darwin_arm_thread_state64_get_fp(ts) \
        ((ts).__fp)
    

    return machineContext->__ss.__lr;引用改为
    return __darwin_arm_thread_state64_get_sp(machineContext->__ss);

    发布版本,framework打包通过

    3.打包测试包

    主工程包不需要打模块framework,此时又引起主工程打包服务器编译问题

    报错:jenkins主工程包报错
    Undefined symbols for architecture armv7:
      "___darwin_arm_thread_state64_get_pc", referenced from:
          +[XXX xxx:] in libXXX.a(xxxxxx.o)
      "___darwin_arm_thread_state64_get_lr",  referenced from:
          +[XXX xxx:] in libXXX.a(xxxxxx.o)
      "___darwin_arm_thread_state64_get_fp",  referenced from:
          +[XXX xxx:] in libXXX.a(xxxxxx.o)
    ld: symbol(s) not found for architecture armv7
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    意思是主工程支持了armv7,打包服务器会编译所有的处理器环境,在armv7环境下,找不到对应的宏

    解决方案:
    去掉armv7环境下对相关宏的引用,代码改为:

    #if defined(__arm64__)
    //    return machineContext->__ss.__sp;
        return __darwin_arm_thread_state64_get_sp(machineContext->__ss);
    #endif
        return 0;
    

    这种改法实际上是懒人改法,因为该组件不需要对armv7环境设备负责,所以在arm64环境下,正常引用对应宏,在其他环境下,直接返回0;

    总结

    • 在没有查看源码时,不知道有__darwin_arm_thread_state64_get_sp这种用法,导致打包失败情况下,查无结果,网上也大多是关于RN相关引用不当的问题,但是RN本身在最新版本修复了这个问题
    • 对于__darwin_arm_thread_state64_get_sp也不是万能的,第三个报错就是在armv7环境下并没有声明这个宏,所以需要进一步对环境进行判断
    • 这部分代码其实并不是组件的业务逻辑内容,但是报错也会造成一定的阻塞,我们都往往只看了XNU对于arm64部分的源码,其实往往忽略了关于 armv7,armv7s,i386和x86相关,在多平台编译问题上,需要更多的了解源码,找到解决问题的答案。

    相关文章

      网友评论

          本文标题:iOS 寄存器编程引起的编译问题

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