到底什么是“objc_msgSend_fixup”?

2023-11-26

我正在摆弄 Objective-C 运行时,尝试编译 Objective-C 代码而不将其链接到libobjc,并且我的程序遇到了一些分段错误问题,因此我从中生成了一个汇编文件。我认为没有必要显示整个汇编文件。在我的某个时刻main函数,我有以下行(顺便说一句,这是我收到段错误之后的行):

callq   *l_objc_msgSend_fixup_alloc

这是定义l_objc_msgSend_fixup_alloc:

.hidden l_objc_msgSend_fixup_alloc # @"\01l_objc_msgSend_fixup_alloc"
    .type   l_objc_msgSend_fixup_alloc,@object
    .section    "__DATA, __objc_msgrefs, coalesced","aw",@progbits
    .weak   l_objc_msgSend_fixup_alloc
    .align  16
l_objc_msgSend_fixup_alloc:
    .quad   objc_msgSend_fixup
    .quad   L_OBJC_METH_VAR_NAME_
    .size   l_objc_msgSend_fixup_alloc, 16

我已经重新实现了objc_msgSend_fixup作为一个函数(id objc_msgSend_fixup(id self, SEL op, ...))返回nil(只是为了看看会发生什么),但是这个函数甚至没有被调用(程序在调用它之前崩溃了)。

所以,我的问题是,什么是callq *l_objc_msgSend_fixup_alloc应该做什么以及什么是objc_msgSend_fixup (after l_objc_msgSend_fixup_alloc:) 应该是(函数或对象)?

Edit

为了更好地解释,我没有将我的源文件链接到 objc 库。我想做的是实现库的某些部分,只是为了看看它是如何工作的。这是我所做的一种方法:

#include <stdio.h>
#include <objc/runtime.h>

@interface MyClass {

}
+(id) alloc;
@end

@implementation MyClass
+(id) alloc {
  // alloc the object
  return nil;
}
@end

id objc_msgSend_fixup(id self, SEL op, ...) {
  printf("Calling objc_msgSend_fixup()...\n");

  // looks for the method implementation for SEL in self's method list

  return nil;   // Since this is just a test, this function doesn't need to do that
}

int main(int argc, char *argv[]) {
    MyClass *m;
    m = [MyClass alloc];    // At this point, according to the assembly code generated
    // objc_msgSend_fixup should be called. So, the program should, at least, print
    // "Calling objc_msgSend_fixup()..." on the screen, but it crashes before
    // objc_msgSend_fixup() is called...

    return 0;
}

如果运行时需要访问对象的 vtable 或对象类的方法列表以找到要调用的正确方法,那么实际执行此操作的函数是什么?我觉得是这样的objc_msgSend_fixup, 在这种情况下。所以,当objc_msgSend_fixup被调用时,它接收一个对象作为其参数之一,如果该对象尚未初始化,则该函数将失败。

所以,我实现了我自己的版本objc_msgSend_fixup。根据上面的汇编源码,应该是可以调用的。该函数是否实际上正在寻找作为参数传递的选择器的实现并不重要。我只是想objc_msgSend_lookup被称为。但是,它没有被调用,也就是说,查找对象数据的函数甚至没有被调用,而不是被调用并导致错误(因为它返回一个nil(顺便说一句,这并不重要))。程序段之前失败objc_msgSend_lookup叫做...

Edit 2

更完整的组装片段:

.globl  main
    .align  16, 0x90
    .type   main,@function
main:                                   # @main
.Ltmp20:
    .cfi_startproc
# BB#0:
    pushq   %rbp
.Ltmp21:
    .cfi_def_cfa_offset 16
.Ltmp22:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
.Ltmp23:
    .cfi_def_cfa_register %rbp
    subq    $32, %rsp
    movl    $0, %eax
    leaq    l_objc_msgSend_fixup_alloc, %rcx
    movl    $0, -4(%rbp)
    movl    %edi, -8(%rbp)
    movq    %rsi, -16(%rbp)
    movq    L_OBJC_CLASSLIST_REFERENCES_$_, %rsi
    movq    %rsi, %rdi
    movq    %rcx, %rsi
    movl    %eax, -28(%rbp)         # 4-byte Spill
    callq   *l_objc_msgSend_fixup_alloc
    movq    %rax, -24(%rbp)
    movl    -28(%rbp), %eax         # 4-byte Reload
    addq    $32, %rsp
    popq    %rbp
    ret

For l_objc_msgSend_fixup_alloc, 我们有:

.hidden l_objc_msgSend_fixup_alloc # @"\01l_objc_msgSend_fixup_alloc"
    .type   l_objc_msgSend_fixup_alloc,@object
    .section    "__DATA, __objc_msgrefs, coalesced","aw",@progbits
    .weak   l_objc_msgSend_fixup_alloc
    .align  16
l_objc_msgSend_fixup_alloc:
    .quad   objc_msgSend_fixup
    .quad   L_OBJC_METH_VAR_NAME_
    .size   l_objc_msgSend_fixup_alloc, 16

For L_OBJC_CLASSLIST_REFERENCES_$_:

.type   L_OBJC_CLASSLIST_REFERENCES_$_,@object # @"\01L_OBJC_CLASSLIST_REFERENCES_$_"
    .section    "__DATA, __objc_classrefs, regular, no_dead_strip","aw",@progbits
    .align  8
L_OBJC_CLASSLIST_REFERENCES_$_:
    .quad   OBJC_CLASS_$_MyClass
    .size   L_OBJC_CLASSLIST_REFERENCES_$_, 8

OBJC_CLASS_$_MyClass是一个指向MyClass结构体定义,它也是由编译器生成的,并且也存在于汇编代码中。


要了解什么objc_msgSend_fixup它是什么以及它做什么 有必要确切地知道 Objective-C 中消息发送是如何执行的。所有 ObjC 程序员有一天都听说过编译器转换[obj message]语句进入objc_msgSend(obj, sel_registerName("message"))来电。然而,这并不完全准确。

为了更好地说明我的解释,请考虑以下 ObjC 片段:

[obj mesgA];
[obj mesgB];

[obj mesgA];
[obj mesgB];

在此片段中,两条消息发送至obj,每个发送两次。因此,您可能会想象生成以下代码:

objc_msgSend(obj, sel_registerName("mesgA"));
objc_msgSend(obj, sel_registerName("mesgB"));
objc_msgSend(obj, sel_registerName("mesgA"));
objc_msgSend(obj, sel_registerName("mesgB"));

However sel_registerName可能成本太高,并且在调用特定方法时调用它并不是明智之举。然后,编译器为每条要发送的消息生成如下结构:

typedef struct message_ref {
    id (*trampoline) (id obj, struct message_ref *ref, ...);
    union {
        const char *str;
        SEL sel;
    };
} message_ref;

因此,在上面的示例中,当程序启动时,我们会看到如下内容:

message_ref l_objc_msgSend_fixup_mesgA = { &objc_msgSend_fixup, "mesgA" };
message_ref l_objc_msgSend_fixup_mesgB = { &objc_msgSend_fixup, "mesgB" };

当这些消息需要发送到obj,编译器生成等效于以下内容的代码:

l_objc_msgSend_fixup_mesgA.trampoline(obj, &l_objc_msgSend_fixup_mesgA, ...);   // [obj mesgA];
l_objc_msgSend_fixup_mesgB.trampoline(obj, &l_objc_msgSend_fixup_mesgB, ...);   // [obj mesgB];

在程序启动时,消息引用蹦床是指向objc_msgSend_fixup功能。对于每个message_ref,当其trampoline第一次调用指针,objc_msgSend_fixup被称为接收obj消息必须发送到的地方message_ref它被称为的结构。所以呢objc_msgSend_fixup必须做的是获取要调用的消息的选择器。因为,对于每个消息引用只需执行一次,objc_msgSend_fixup还必须更换trampolineref 的字段通过指向另一个不修复消息选择器的函数的指针。这个函数称为objc_msgSend_fixedup(选择器已修复)。现在消息选择器已设置,无需再次执行此操作,objc_msgSend_fixup只是打电话objc_msgSend_fixedup这只是调用objc_msgSend。之后,如果消息引用trampoline再次被调用,它的选择器已经固定,并且objc_msgSend_fixedup是被调用的那个。

简而言之,我们可以写objc_msgSend_fixup and objc_msgSend_fixedup像这样:

id objc_msgSend_fixup(id obj, struct message_ref *ref, ...) {
    ref->sel = sel_registerName(ref->str);
    ref->trampoline = &objc_msgSend_fixedup;
    objc_msgSend_fixedup(obj, ref, ...);
}

id objc_msgSend_fixedup(id obj, struct message_ref *ref, ...) {
    objc_msgSend(obj, ref->sel, ...);
}

这使得消息发送速度更快,因为只有在第一次调用消息时才会发现适当的选择器(通过objc_msgSend_fixup)。在以后的调用中,选择器将已经被找到,并且消息被直接调用objc_msgSend (by objc_msgSend_fixedup).

在问题的汇编代码中,l_objc_msgSend_fixup_alloc is the alloc方法message_ref结构和分段错误可能是由其第一个字段中的问题引起的(也许它没有指向objc_msgSend_fixup...)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

到底什么是“objc_msgSend_fixup”? 的相关文章

  • 在 cocoa touch 中以编程方式将视图位置设置为右上角

    我需要确保一个视图 A 尺寸 200x200 始终与第二个视图 B 全屏尺寸 内的右上角对齐 我想确保无论设备方向如何 视图 A 都保留在该位置 事实是 当使用界面生成器来定位视图时 我对此没有任何问题 但我需要以编程方式构建它 我想我应该
  • 如何在 Swift 中调用 Objective-C 实例类型方法?

    我有一个 Objective C 类 如下所示 interface CustomObjectHavingData NSObject property nonatomic strong NSData objWithData instancet
  • 如何在 GCC C++ 中编写多行内联汇编代码?

    这看起来不太友好 asm command 1 command 2 command 3 我真的必须在每一行加上双引号吗 另外 由于多行字符串文字在 GCC 中不起作用 我也无法欺骗它 我总是在互联网上找到一些例子 该人手动插入制表符和换行符而
  • UITextField 的自定义字体在编辑模式下发生变化

    我有一个UITextField这是从 xib 加载的 在它的视图控制器中viewDidLoad方法中 我将字体设置为自定义值 该值在 plist file和所有 它显示良好 除非处于编辑模式 此时字体从我的自定义字体切换为默认字体 我认为这
  • 如何在 iOS 上捕获的视频中添加水印[重复]

    这个问题在这里已经有答案了 我想知道是否有人可以告诉我如何实现这一目标 如果一直在考虑几个解决方案 从捕获的视频创建单独的图像 然后将它们合并到每个图像中 然后创建一个新的 AVAsset 听起来有点复杂 您不觉得吗 合并2个视频 一个是透
  • 简单的 iPhone 运动检测

    我需要检测陀螺仪 加速度计何时被激活一定量 基本上是检测设备何时移动 我对核心运动一无所知 也许有人可以指导我入门教程或其他东西 提前致谢 我认为你必须使用 Core Motion 好消息是 它对于您的问题域来说并不难使用 开始阅读事件处理
  • IBOutlet、实例变量和属性:最佳实践

    今天 我对有关声明 IBOutlet 和实例变量 管理它们 使用正确的访问器以及正确释放它们的最佳实践进行了各种研究 我已经差不多了 但我有一些小问题 我希望有人能够就最佳实践提出建议 我会将它们格式化为代码并注释问题 以便更容易理解 我排
  • 调用可以是 cdecl 或 stdcall 的函数

    我需要编写调用外部函数的代码 该函数可以是 32 位 Windows 应用程序中的 stdcall 调用或 cdecl 我的代码 调用者 无法提前知道其中的哪一个 现在 如果我尝试从定义为 stdcall 的调用站点调用 cdecl 函数
  • 理解 Objective-C 中选择器的唯一性

    我无法理解 选择器 的部分功能 如苹果指南中所述 我把我感到困惑的部分加粗了 在 Objective C 中 选择器有两个含义 可以用来参考 当在源代码消息中使用方法时 只需使用方法的名称 到一个物体 不过 它也指的是唯一标识符 编译源代码
  • UIAlertAction 处理程序在延迟后运行

    我正在尝试将 UIAlertViews 更改为 UIAlertControllers 我为此设置了这个操作 UIAlertAction undoStopAction UIAlertAction actionWithTitle Undo St
  • 使用 Facebook API 和 Objective C 来查找随机 Facebook 用户图像

    我正在构建一个返回随机 Facebook 个人资料图片的应用程序 到目前为止 我有下面的代码生成一个随机个人资料 ID 有时会返回真实的个人资料 但有时不会 只显示通用的蓝色 Facebook 面孔 当我在实际网站图形 API 上使用给定的
  • 为什么我无法更改 UIBarButtonItem 的标题?

    我想改变UIBarButtonItem s title 但这段代码不起作用 void viewDidLoad self smay void smay AppDelegate apd AppDelegate UIApplication sha
  • 如何使用呼叫目录扩展来识别应用程序中的来电?

    我正在研究callKit框架 我发现通过使用呼叫目录扩展 我们可以识别来电电话号码 我的问题是如何在 iOS 应用程序中实现呼叫目录扩展来识别来电详细信息 我在 Objective C 工作 让一个数 919876xxxxx 使用此方法添加
  • 在后台运行 URL 请求

    我想在一定的时间间隔内发出 url 请求 例如 每 10 分钟应用程序应该发出一次 url 调用并获取一些 json 数据 应用程序在后台运行时应该能够执行此操作 这可以做到吗 如果是这样 这是否违反 Apple 服务条款 有什么限制吗 i
  • Xcode 中的 NSObject 描述和自定义摘要

    我覆盖对象的 NSString description但是 Xcode 总是显示error summary string parsing error在变量视图的摘要字段中 我当前的实现如下 NSString description retu
  • 如何使用固定宽度和自动布局正确缩放图像?

    我有一个动态 UIImage 和一个固定宽度为 280 0px 的 UIImageView 并且我正在使用自动布局 在 UIImage 视图上 我设置了宽度和高度约束 并降低了高度约束的优先级 我选择了 aspect fit 并将内容拥抱和
  • 如何将NSTextView的格式化内容转换为字符串

    我需要将 NSTextView 的内容从 Mac 应用程序传输到 iOS 应用程序 我使用 XML 作为传输文件格式 所以我需要将 NSTextView 的内容 文本 字体 颜色等 保存为字符串 有什么办法可以做到这一点吗 一种方法是存档
  • 播放循环声音的最简单方法是什么?

    在 iPhone 应用程序中播放循环声音的最简单方法是什么 可能最简单的解决方案是使用AVA音频播放器 http developer apple com library ios DOCUMENTATION AVFoundation Refe
  • ObjectiveC 和 JavaScriptCore:使用这种调用回调的方法会导致内存问题吗?

    免责声明 这是一篇很长的文章 但对于那些努力使用新的 ObjectiveC JavascriptCore 框架并在 ObjC 和 JS 之间进行异步编码的人来说可能非常有价值 您好 我对 Objective C 非常陌生 正在将 javas
  • 使用 MPMoviePlayerViewController 时的 iPad 旋转错误

    问题摘要 使用 MPMoviePlayerViewController 播放视频时更改 iPad 设备或模拟器的方向会导致视频播放器关闭时旋转状态不一致 这是 iPad SDK 3 2 中的一个已知错误 记录于http www openra

随机推荐

  • 为什么 MobX v6.x 在 React with Typescript 中不能按预期工作?

    我目前正在编写一个 React 应用程序 它应该能够在任何可观察到的值发生变化时重新渲染组件 问题是我无法得到email如果发生变化则重新渲染 store ts export class ExampleStore observable em
  • RewriteRule - 两个参数,但最后一个参数是可选的

    我无法重写以包含两个参数 但最后一个参数是可选的 例如 http www mywebsite com friends jamie 正斜杠也应该是可选的 这应该与此相同 http www mywebsite com friends php n
  • 隐藏奇怪的不需要的 Xcode 日志

    使用 Xcode 8 并创建新的空白项目时 运行应用程序时会出现以下日志 2016 06 13 16 33 34 406093 TestiOS10 8209 100611 bundleid com appc TestiOS10 enable
  • 在数据库中的任意位置查找值

    给定一个数字 我如何发现它可以在哪个表和列中找到 我不在乎它是否快 它只需要工作 这可能对你有帮助 来自纳拉亚纳 维亚斯 它搜索给定数据库中所有表的所有列 我以前用过它并且有效 这是上面链接中的存储过程 我所做的唯一更改是用临时表替换表变量
  • 有没有办法自动占据WrapPanel中的空白区域?

    WrapPanel 的子级按顺序填充 如所附屏幕截图所示 因此 Panel根据每个孩子的身长 制作了较长的空白 如何利用空白空间重新排列孩子们 到目前为止 似乎只有很少的人使用 WrapPanel 并且没有足够的示例 有一些自动的方法吗 或
  • EXECUTE 后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。先前计数

    我收到有关提交和回滚的异常 但不确定我的存储过程到底出了什么问题 我已阅读其他此类问题的答案 但无法找到提交计数到底在哪里混乱 所以 这是我使用的存储过程 this is a procedure used for the purge uti
  • 如何配置 leiningen 以使用最新的 Clojure 版本来在项目之外启动 repl?

    当我为特定项目启动 clojure repl 时 对于 leiningen 来说足以在具体中指定正确的 clojure 版本项目 clj如上所述的文件here 但是当我在项目之外启动 repl 时 旧版本就会启动 就我而言 旧版本是1 5
  • Airflow安装成功,但无法运行

    C Python27 Scripts gt airflow initdb airflow 不被识别为内部或外部命令 可运行的程序或批处理文件 C Python27 Scripts gt 气流初始化 airflow 不被识别为内部或外部命令
  • 如何从 Hibernate MetadataSources 发现完全限定的表列

    我有一个实体 我有一个实体Class
  • C# 的线程是在用户级还是内核级创建的?

    最近在研究操作系统 遇到了这个问题 线程是在C 用户级还是内核级创建的 比如 Thread mythread new Thread ThreadStart something 据我所知 内核级CPU密集型线程的进程可以比用户级别的运行速度更
  • 如何在 Mono 上将 Linq 与 MySql 数据库结合使用?

    有许多库为与 MySql 数据库交互的 C 代码提供 Linq 功能 其中哪一个在 Mono 上最稳定 最可用 背景 大部分不相关 我有一个简单的 C Net 2 0 程序 用于更新 MySql 数据库中的值 它每晚通过 cron 作业执行
  • Facebook SDK FB.GetLoginStatus 加载被 X-Frame-Options 拒绝(仅限 Firefox)

    我有一个 Web 应用程序登录页面 在文档加载完成后 该页面会从 Facebook JavaScript SDK 调用 FB GetLoginStatus 这在所有浏览器 包括移动设备 上都运行得很好 从此以后就很幸福了 但是 有一天 我突
  • Akka 持久化查询事件流和 CQRS

    我正在尝试在我的 ES CQRS 架构中实现读取端 假设我有一个这样执着的演员 object UserWrite sealed trait UserEvent sealed trait State case object Uninitial
  • 在 cakePHP 2.x 中使用虚拟字段

    我已通读文档并努力了解该怎么做 另外 我已经阅读了 stackoverflow 上的问题 但我尝试的任何方法都没有帮助 我有一个下拉列表 我想列出公司中的所有员工 该列表应显示如下 Name Surname Job Title 在我的模型中
  • 使用 Python / lxml 和 XPath 检索属性名称和值

    我将 XPath 与 Python lxml Python 2 一起使用 我对数据进行了两次处理 一次用于选择感兴趣的记录 另一次用于从数据中提取值 这是代码类型的示例 from lxml import etree xml
  • UTF-8 到 Unicode 代码点

    是否有一个函数可以将 UTF 8 更改为 Unicode 将非特殊字符保留为普通字母和数字 即德语单词 tch 将被渲染为 tch 20AC 21AC 请注意 我正在编写 Unicode 代码 编辑 我正在尝试以下函数 但是尽管该函数适用于
  • 获取调用方法的对象

    如果我有一个来自随机班级的电话 如下所示 implementation SomeClass void classMethodFoo int a SomeSingleton sharedInstance aValue end Inside S
  • 可以向 Google Maps API 发出多少个请求而不被禁止?

    我正在通过 Google Maps API 使用地址自动建议 希望速度尽可能快 目前 我在脚本中添加了 10 毫秒的延迟 以避免因太多请求而被禁止 有这个必要吗 可以提出多少个请求而不被禁止 附 我希望为此添加一些合适的标签 但我真的想不出
  • 如何在 Hibernate 查询语言中执行左连接?

    这是我的 HQL 查询 但它不起作用并且抛出错误 Hql查询 SELECT FROM TABLEA A LEFT JOIN A TABLEB B WHERE A COLUMNNAME B COLUMNAME 它会导致此错误 org hibe
  • 到底什么是“objc_msgSend_fixup”?

    我正在摆弄 Objective C 运行时 尝试编译 Objective C 代码而不将其链接到libobjc 并且我的程序遇到了一些分段错误问题 因此我从中生成了一个汇编文件 我认为没有必要显示整个汇编文件 在我的某个时刻main函数 我