【问题标题】:objc_msgSend and unionsobjc_msgSend 和联合
【发布时间】:2013-07-15 19:12:45
【问题描述】:

当我有返回某个联合的方法时,我遇到了与 objc_msgSend 运行时调用相关的问题。

我正在通过 libffi 调用 objc_msgSend 函数,如果我的 union 小于 16B,一切正常,但如果 union 的大小大于 16B,我会遇到 seg 错误。 我尝试使用 objc_msgSend_stret 函数,它通过了,但是我得到了返回联合的错误值,我不确定哪个函数调用了联合。

有没有人知道关于目标 c 中的联合,它们在 objc 运行时是如何处理的?

【问题讨论】:

  • 当您使用 objc_msgSend 时,这是一个 HUUUUGE 问题;基本上,ARM(假设这是针对 iOS 的)喜欢将其返回值放在寄存器中,但有些对象无法放入寄存器中。你需要打电话给objc_msgSend_stret,而不是用你希望你的工会被塞进的地址。 developer.apple.com/library/mac/documentation/Cocoa/Reference/…
  • 这是用于什么平台的? iOS?

标签: objective-c objective-c-runtime


【解决方案1】:

当您使用objc_msgSend 时,这是一个HUUUUGE 问题;基本上,大多数 ABI 都喜欢将它们的返回值放在寄存器中(这里是勇敢和好奇的所有血腥细节:http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/000-Introduction/introduction.html)但有些对象无法放入寄存器(这就是为什么联合大小 objc_msgSend_stret,而不是使用您希望将工会塞入的地址。

另一个很好的参考:http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/c/func/objc_msgSend_stret

解决方案:不要强制转换和调用objc_msgSend,而是强制转换和调用objc_msgSend_stret

void objc_msgSend_stret(void * stretAddr, id theReceiver, SEL theSelector,  ...)

所以你的演员将是(如using objc_msgSend to call a Objective C function with named arguments):

union myUnion {
    int a, b;
    char c;
    double d;
};

// For objc_msgSend_stret
void (*objc_msgSend_stretTyped)(union myUnion* stretAddr, id self, SEL _cmd, float bar) = (void*)objc_msgSend_stret;

union myUnion u;
float pi = 4;

objc_msgSend_stretTyped(&u, obj, sel_getUID(sel), pi);

EDIT -- 跳过以上所有代码

这是我设法让 objc_msgSend_stret 工作的方法:

#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/objc.h>

@interface ViewController ()

@end

union myUnion {
    int myArray[32];
    int a,b,c,d;
};

void doStuff(id obj, SEL sel);

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    doStuff(self, @selector(doStuff:));
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (union myUnion) doStuff: (int)myInt {
    NSLog(@"Pi equals %d", myInt);
    union myUnion u;
    for(int i=0; i<32; i++) {
        u.myArray[i] = i*i*i*i-1;
    }
    return u;
}

@end

void doStuff(id obj, SEL sel) {
    int pi = 4;
    NSLog(@"myUnion is: %luB", sizeof(union myUnion));
    NSLog(@"Sizeof(int) = %luB ... Sizeof(char) = %lub ... sizeof(double) = %luB", sizeof(int), sizeof(char), sizeof(double));

    union myUnion u = ((union myUnion(*)(id, SEL, int))objc_msgSend_stret)(obj, sel, pi);
    NSLog(@"Union u = {%d, %d, %d, %d}", u.myArray[30], u.myArray[29], u.myArray[28], u.myArray[27]);
}

【讨论】:

  • 寄存器中返回的小结构通常是正确的,除了 PPC,根据 Greg Parker sealiesoftware.com/blog/archive/2008/10/30/…。完整的详细信息在 Apple 的 ABI 参考中。
  • @Josh,啊!!我正试图找到那篇文章(我记得仓鼠!)......我知道我忘记了一些重要的事情!
  • 您为 objc_msgSend_stretTyped() 转换的函数指针是错误的。您需要将其转换为返回结构的函数指针。在某些 ABI 上,返回结构的函数与返回带有结构指针参数的 void 的函数不同。
  • tnx 你们的答案...我知道关于 ABI-s 和 objc_msgSend/objc_msgSend_stret 调用的故事,它们并不总是将结果保存在寄存器中,但我的问题实际上与 libffi 和处理有关libffi 中的工会。看来我们需要指定 FFI_TYPE_STRUCT 类型的大小,以便 objc_msgSend 与 libffi 一起工作 :)
  • 但是我仍然有问题:(。如果您尝试运行返回大于 16B 的联合的方法,xcode 仍然会调用成功的 objc_msgSend 函数,如果我们尝试调用 objc_msgSend_stret 函数则会崩溃,即使我们有大小的联合,例如 300B....但是对于 libffi,情况有点不同。
猜你喜欢
  • 1970-01-01
  • 2016-01-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 2016-06-20
  • 2019-10-24
  • 1970-01-01
  • 2017-03-14
相关资源
最近更新 更多