如何隐藏objective-c库中的对象

mto*_*toy 5 objective-c static-libraries

我正在尝试创建一个用Objective-C编写的静态库.我想隐藏这个库的消费者的所有实现细节.在此示例中,"OneThing"对象使用库内部的其他功能,包括"SecretThing",它可能被库中的许多内容使用(并且不能隐藏在OneThing内部).但是我不希望库的用户看到OneThing使用SecretThing,或者甚至存在SecretThing,即使他们在.a文件中查找.

@interface OneThing
+ (void) do;
@end
@interface SecretThing
+ (void) undo;
@end
@implementation OneThing
+ (void) do
{
    [SecretThing undo];
}
@end
@implementation SecretThing
+ (void) undo { }
@end
Run Code Online (Sandbox Code Playgroud)

如果我们编译它,并检查符号表:

% cc -c onething.m
% nm onething.o | grep Thing
0000000000000000 t +[OneThing do]
00000000000002f8 s +[OneThing do].eh
0000000000000040 t +[SecretThing undo]
0000000000000320 s +[SecretThing undo].eh
0000000000000078 S _OBJC_CLASS_$_OneThing
0000000000000050 S _OBJC_CLASS_$_SecretThing
00000000000000a0 S _OBJC_METACLASS_$_OneThing
00000000000000c8 S _OBJC_METACLASS_$_SecretThing
0000000000000128 s l_OBJC_$_CLASS_METHODS_OneThing
00000000000001d8 s l_OBJC_$_CLASS_METHODS_SecretThing
0000000000000190 s l_OBJC_CLASS_RO_$_OneThing
0000000000000240 s l_OBJC_CLASS_RO_$_SecretThing
0000000000000148 s l_OBJC_METACLASS_RO_$_OneThing
00000000000001f8 s l_OBJC_METACLASS_RO_$_SecretThing
% 
Run Code Online (Sandbox Code Playgroud)

正如我们所料,我们看到OneThing和SecretThing同样暴露.现在以某种方式解决SecretThing的内部到库的使用并且仅将OneThing暴露给外部世界会很棒.我想要的是这个(选择一种方法来尝试和管理):

% ld -r onething.o -exported_symbol "+[OneThing do]" -o onlyonething.o
Run Code Online (Sandbox Code Playgroud)

我希望这会将"+ [OneThing do]"标记为类型"T"(文本全局),然后它将在"条带"中存活.它不是.这让我很烦,因为我认为这在某个时间点起作用,也许当我更新工具链时,我得到了一个新版本的ld("ld -v"== ld64-133.3),它的工作方式不同.

除了将源代码发送到链接器并编写自己的新标志以执行我想要的操作之外,我没有想法.我希望我只是愚蠢而且有一些我不明白的东西让这更容易.


在答案中,有人认为这基本上是不可能的,因为您需要在运行时可用的所有链接信息来进行方法分派.我相信这个实验证明这不是真的.

# Move OneThing and SecertThing into their own files, with their own .h
% cat c_api.m
#include "OneThing.h"

void one_thing_do()
{
    [OneThing do];
}
% cc -c c_api.c
% cat main.m
int main(int argc, char**argv)
{
    extern void one_thing_do();

    one_thing_do();
}
% cc main.m c_api.o onething.o secretthing.o -framework Foundation
% ./a.out
% ( runs to completion, no errors )
Run Code Online (Sandbox Code Playgroud)

现在我们尝试隐藏我们不希望世界看到的部分:

% ld -r c_api.o onething.o secretthing.o -o strip_c_api.o -exported_symbol "_one_thing_do"
% strip -x c_strip_c_api.o
% nm strip_c_api.o
0000000000000118 s EH_Frame1
0000000000000098 s EH_Frame1
00000000000000d8 s EH_Frame1
                 U __objc_empty_cache
                 U __objc_empty_vtable
                 U _objc_msgSend
0000000000000000 T _one_thing_do
0000000000000130 s func.eh
00000000000000f0 s func.eh
00000000000000b0 s func.eh
0000000000000020 t l001
0000000000000060 t l002
0000000000000170 s l003
0000000000000190 s l004
00000000000001d8 s l005
0000000000000220 s l006
0000000000000240 s l007
0000000000000288 s l008
00000000000002f0 s l009
0000000000000318 s l010
0000000000000340 s l011
0000000000000368 s l012
% clang main.m strip_c_api.o -framework Foundation
% ./a.out
% nm a.out
0000000100001280 S _NXArgc
0000000100001288 S _NXArgv
0000000100001298 S ___progname
0000000100000000 T __mh_execute_header
                 U __objc_empty_cache
                 U __objc_empty_vtable
0000000100001290 S _environ
                 U _exit
0000000100000db0 T _main
                 U _objc_msgSend
0000000100000de0 T _one_thing_do
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000d70 T start
Run Code Online (Sandbox Code Playgroud)

Jus*_*Sid 6

由于Objective-C运行时的动态方式,这是不可能的.运行时需要这些信息来实例化类并向其发送消息,因此实际上没有办法在不破坏库的情况下隐藏这些信息.