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

一、寄存器编程代码

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相关,在多平台编译问题上,需要更多的了解源码,找到解决问题的答案。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容