gpt4 book ai didi

objective-c - 从 i386 和 ARM 程序集中的堆栈中删除参数

转载 作者:太空狗 更新时间:2023-10-30 03:33:50 33 4
gpt4 key购买 nike

我正在使用一些 trampoline 函数,以便在 C/Objective-C 中进行更高级别的调用,过程中有一点小转折 Apple does it .

如果您完全熟悉 Objective-C IMP 的工作方式,它基本上是一个函数指针,其中前两个参数是消息的接收者和消息选择器的名称,例如 void(*)(id obj, SEL sel, ...)。运行时的更新版本允许在运行时使用 C block 合成方法实现,例如 void(^)(id obj, ...)。这些 block 没有选择器;运行时创建一个蹦床,用接收器覆盖选择器,用 block 指针覆盖接收器,然后继续执行它。

我想做一些大致相似的事情,其中​​不包括前两个参数中的任一个,因此这个 block 的参数与传统方法 send 的参数完全相同,加上用于执行目的的 block 指针,即 void(*)(Block *, ...)。这只需要复制 block 指针,我想去掉一个参数。

__a1a2_tramphead_argonly:
popl %eax
andl $0xFFFFFFF8, %eax
subl $0x1000, %eax
movl 4(%esp), %ecx // self -> ecx
movl %ecx, 8(%esp) // ecx -> _cmd
movl (%eax), %ecx // blockPtr -> ecx
movl %ecx, 4(%esp) // ecx -> self
jmp *12(%ecx) // tail to block->invoke

这是我在 ARM 上的程序集:

__a1a2_tramphead_argonly:
// calculate the trampoline's index (512 entries, 8 bytes each)
#ifdef _ARM_ARCH_7
// PC bias is only 4, no need to correct with 8-byte trampolines
ubfx r1, r1, #3, #9
#else
sub r1, r1, #8 // correct PC bias
lsl r1, r1, #20
lsr r1, r1, #23
#endif

// load block pointer from trampoline's data
adr r12, __a1a2_tramphead_argonly // text page
sub r12, r12, #4096 // data page precedes text page
ldr r12, [r12, r1, LSL #3] // load block pointer from data + index*8

// shuffle parameters
mov r1, r0 // _cmd = self
mov r0, r12 // self = block pointer

// tail call block->invoke
ldr pc, [r12, #12]

x86_64 存在类似的代码;上面的代码目前直接来自 Apple。就个人知识而言,我想知道从哪里开始删除一个参数,以便第一个参数(曾经是接收者)是 block 文字,第二个是第一个真正的参数,依此类推。

我对 ASM 非常陌生,所以非常感谢任何帮助。我尝试过的一切都以越来越有趣的方式爆炸了。提前致谢。

最佳答案

iOS ABI 有效地结合了 AAPCS 并且只定义了差异,因此您需要从 http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0042d/index.html 开始第一的。然后阅读 Apple 的 iOS ABI 函数调用指南(我认为您需要付费的 iOS 开发中心成员(member)才能访问)。

总结规则,调用 ObjC IMP:

  • 自己进入R0
  • _cmd 进入 R1
  • 第一个 int 或指针参数进入 R2
  • 第二个 int 或指针参数进入 R3
  • 所有进一步的参数都入栈

因此,如果您只查看最多 2 个参数的参数,没有一个是 float /int64_t/struct,删除 self 和 _cmd 参数只是洗牌 R0-R4 的问题:

mov r0, r2
mov r1, r3

或者,要编写一个带有两个参数并在转发到 IMP 之前塞入 self 和 _cmd 的函数,就是这样:

mov r3, r1
mov r2, r0
ldr r1, [address of _cmd]
ldr r0, [address of self]

就 Apple 的 block trampoline 而言,他们正在做的是将对 [foo performBlockOnSelf:block] 的调用有效地转换为 [block foo]。正如您所说, block 指针在 r0 (通常的 self 位置)结束,目标参数 foo 在 r1 (通常的 _cmd 位置)结束。如果 block 真的是 IMP,当然,这将是无稽之谈,因为 foo 不是 SEL,但它们不是,所以这不是问题。

从你的陈述“我想做一些模糊相似的事情,其中​​不包括前两个参数中的任何一个,因此这个 block 的参数与传统方法 send 的参数完全相同,”我不是完全清楚您要尝试做的两件事中的哪一件:

  1. 定义一个“委托(delegate)”对象(在 C# 术语中),基本上是一个 block ,其目标在构建时被嵌入。在这种情况下,您需要从一些委托(delegate)表中同时查找 r0( block 指针)和 r1(目标),而不仅仅是 block 指针。但是您不会有任何编译器帮助设置该表——这意味着您可以在纯 C 中设置和访问它,并且它与构建自定义汇编蹦床一样方便。 (您甚至可以通过 ObjC 字典来完成,但在实践中可能会损失一些性能。)

  2. 将常规消息转换为 block ,这涉及存储所有内容,以便当 Apple 的 trampoline 代码尝试调用 block 时,它以传统方法发送参数而不是 block 参数结束。如果这是您的目标,那么只在消息周围使用 block 包装器而不是尝试将消息转换为 block 会更简单、更安全,我怀疑效率或灵 active 成本是否重要。

    <

关于objective-c - 从 i386 和 ARM 程序集中的堆栈中删除参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9971067/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com