如何在非脏内存中创建链接器解析的数据表
Posted
技术标签:
【中文标题】如何在非脏内存中创建链接器解析的数据表【英文标题】:How to create a table of linker-resolved data in non-dirty memory 【发布时间】:2017-10-10 17:43:13 【问题描述】:我想创建一个数据表,并将其保存在非脏内存中(这样该表就不会影响 ios 和相关平台 (tvOS/watchOS) 上的应用程序的内存使用量)。
表格是一个包含两条数据的数组:Objective-C 类和一个数值:
#include <Foundation/Foundation.h>
struct TypeMap
Class class;
int value;
;
我想做这样的事情:
struct TypeMap map [] =
[NSObject class], 0x1234
;
但这显然不起作用,clang 抱怨:
test.m:9:4: error: initializer element is not a compile-time constant
[NSObject class], 0x1234
^~~~~~~~~~~~~~~~
这当然是完全有道理的,因为[NSObject class]
不是编译时常量。
但是有一个动态加载器能够解析的符号:_OBJC_CLASS_$_NSObject
,这让我想到了这样的事情:
extern Class OBJC_CLASS_$_NSObject;
struct TypeMap map [] =
OBJC_CLASS_$_NSObject, 0x1234
;
这个想法是动态链接器可以在运行时解析符号,然后将内存标记为只读(与普通代码的工作方式相同)。
不幸的是它遇到了同样的问题:
test.m:11:4: error: initializer element is not a compile-time constant
OBJC_CLASS_$_NSObject, 0x1234
^~~~~~~~~~~~~~~~~~~~~
我确信我可以用汇编代码表达这一点,但我想尽可能避免汇编并坚持使用 Objective-C(无需每个平台实现一次)。
我在这里完全偏离轨道了吗?这甚至可能吗?
更新
工作版本:
// clang test.m -framework Foundation
#include <Foundation/Foundation.h>
#include <objc/objc.h>
#include <objc/runtime.h>
struct TypeMap
Class class;
int value;
;
extern void* OBJC_CLASS_$_NSObject;
const struct TypeMap map [] =
(Class) &OBJC_CLASS_$_NSObject, 0x1234 ,
;
int main ()
printf ("%s %p %i\n", class_getName (map[0].class), map [0].class, map [0].value);
return 0;
【问题讨论】:
c
-标签是有原因的,还是您只是觉得它美观?
我不熟悉“非脏内存”这个词。在上下文中,我相信您的意思是“只读数据段”,但我不是 100% 确定。请澄清。
@zwol:我所说的非脏内存是指 iOS 可以分页的内存(并且不会计入应用程序的内存限制)。请参阅***.com/a/19238896/183422 以获得更深入的解释。
【参考方案1】:
如果我理解正确的话,Objective-C 中的 Class
是 aggregate type,在 C 标准使用该术语的意义上。那么,给定
struct TypeMap
Class class;
int value;
;
extern Class OBJC_CLASS_$_NSObject;
struct TypeMap map [] =
OBJC_CLASS_$_NSObject, 0x1234
;
您要求动态加载器在加载时将聚合复制到您的数据结构中,这不是它所具有的功能。
您应该能够做的是让您的 TypeMap 包含 指针 到 OBJC_CLASS_$_...
符号:
struct TypeMap
Class *class;
int value;
;
extern Class OBJC_CLASS_$_NSObject;
const struct TypeMap map[] =
&OBJC_CLASS_$_NSObject, 0x1234 ,
// ...
;
试一试,看看效果如何。
(注意在map
的声明中添加的const
- 您需要首先将此数据结构放入只读数据段中。)
【讨论】:
答案不是 100% 正确,因为符号似乎是聚合数据。这意味着这是工作版本:struct TypeMap Class class; int value; ; extern void* OBJC_CLASS_$_NSObject; struct TypeMap map [] = (Class) &OBJC_CLASS_$_NSObject, 0x1234 , ;
进一步的测试表明,虽然它可以编译,但它并没有解决我的问题:仪器显示数据最终成为脏内存。如果我用代码编写它(一个带有巨大 switch 语句的方法),那么它最终不会成为脏内存,所以这在技术上显然是可行的。
@RolfBjarneKvinge 对不起,我对 Objective-C 或 iOS 编程环境的了解还不够,无法进一步帮助您。您应该提出一个新问题,突出您的“struct TypeMap”和巨型开关语句方法之间的对比。以上是关于如何在非脏内存中创建链接器解析的数据表的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C 中创建 AT 命令解析器以获取来自 USART1 的传入字符串?