【问题标题】:How do I do inline assembly on the IPhone?如何在 iPhone 上进行内联汇编?
【发布时间】:2010-09-19 06:37:39
【问题描述】:

它是如何完成的?我需要采取哪些步骤以及需要考虑哪些陷阱和陷阱?

【问题讨论】:

  • 问得好,我很想看看回复。

标签: iphone assembly inline-assembly


【解决方案1】:

我写了很多 ARM Cortex-A8 汇编代码。 iPhone 上的 CPU 是 ARM11 (afaik),所以核心指令集是一样的。

您到底在寻找什么?如果你愿意,我可以给你一些例子。


编辑:

我刚刚发现在 iPhone 上你必须使用 llvm-gcc 编译器。据我所知,它应该理解 GCC 的内联汇编语法。如果是这样,所有 ARM 内联汇编器教程也可以在 iPhone 上运行。

这是一个非常小的内联汇编函数(C 语言)。你能告诉我它是否可以在 iphone 上编译和工作吗?如果它有效,我可以咆哮一下如何在 ARM 内联汇编器中做有用的事情,特别是对于 ARMv6 架构和 DSP 扩展。

inline int saturate_to_255 (int a)
{
  int y;
  asm ("usat %0, #8, %1\n\t" : "=r"(y) : "r"(a));
  return y;
}

应该相当于:

inline int saturate_to_255 (int a)
{
  if (a < 0) a =0;
  if (a > 255) a = 255;
  return a;
}

【讨论】:

  • 我无法编译这个。我一直在尝试通过 Apple 的 XCode。编译器实际上默认设置为 GCC 4。如果我使用它编译它会抱怨无效指令“usat”,如果我将其设置为使用 llvm-gcc,则会抱怨无效架构“armv6”。
  • 试试 gcc -O3 -march=armv6 test.c
  • llvm-gcc 不就是一个针对 llvm 虚拟机的编译器吗?
  • 是的,但是 llvm 有一个 ARM 代码生成器后端,因此您可以使用它来编译真实代码以及 llvm 字节码。
  • 这可以毫无问题地使用工具链进行编译。我很想听到一些关于有用的内联汇编器的咆哮!
【解决方案2】:

感谢Apple Devforums 的一些内部帮助,我已经完成了这项工作,如果您是专门的 iPhone 开发人员,您应该注册。

首先,它是 __asm__(),而不是普通的 asm()

其次,默认情况下,XCode 会生成一个针对 ARM Thumb 指令集编译内联汇编的编译目标,因此 usat 未被识别为正确的指令。要解决此问题,请在目标上执行“获取信息”。向下滚动到“GCC 4.0 - 代码生成”部分并取消选中“Compile for Thumb”。如果将 Active SDK 设置为“设备”,那么下面的 sn-p 将编译得很好

inline int asm_saturate_to_255 (int a) {
  int y;
  __asm__("usat %0, #8, %1\n\t" : "=r"(y) : "r"(a));
  return y;
}

当然,现在它不适用于 iPhone 模拟器。但是TargetConditionals.h 已经定义了你可以#ifdef 反对。即TARGET_OS_IPHONETARGET_IPHONE_SIMULATOR

【讨论】:

  • 我认为你的意思是 __asm__() 而不是普通的 asm()。
  • 为什么它不适用于 iPhone 模拟器?是没有汇编在模拟器上工作,还是因为它在 i386 上运行而必须有一组不同的汇编指令?
  • @Roberto:你明白了。模拟器在 x86 上运行,所以不能运行 ARM 程序集。它只是不会编译。
【解决方案3】:

Thumb 推荐用于不需要大量浮动操作的应用。 Thumb 使代码更小,代码执行速度也更快。

所以你应该只为 3D 游戏之类的应用程序关闭 Thumb...

【讨论】:

【解决方案4】:

寄存器也可以在 inline asm 中显式使用

void foo(void) {
#if TARGET_CPU_ARM64
    __asm ("sub        sp, sp, #0x60");
    __asm ("str        x29, [sp, #0x50]");
#endif
}

【讨论】:

    【解决方案5】:

    背景

    • 现在是 2021 年 -> 其他答案似乎太旧了?
    • 大多数iOS设备(iPhone等)是ARM 64bit:arm64

    iPhone 上的内联汇编

    asm 关键字

    • GNU/GCC 编译器
      • 标准C(编译标志:-ansi/-std):使用__asm__
      • GNU 扩展:使用asm
    • ARM 编译器:使用__asm

    asm 语法

    AFAIK,有很多 asm 语法

    • asm 语法
      • AT&amp;T syntax ~= GNU syntax ~= UNIX syntax
      • Intel syntax
      • ARM syntax

    这里只关注最常用的GNU/GCC语法

    GNU/UNIX syntax

    基本汇编

    asm("assembly code");
    __asm__("assembly code");
    

    扩展汇编

    asm asm-qualifiers ( AssemblerTemplate 
                     : OutputOperands 
                     [ : InputOperands
                     [ : Clobbers ] ])
    

    我的示例代码

    • 环境
      • 开发
        • macOS
          • IDE:XCode
            • 编译器:clang
      • 正在运行
        • iOS - iPhone
          • 硬件拱门:ARM64

    使用扩展 Asm 为 ARM64 调用 svc 0x80 的内联 asm

    • ObjC 代码中的内联汇编
    // inline asm code inside iOS ObjC code
    __attribute__((always_inline)) long svc_0x80_syscall(int syscall_number, const char * pathname, struct stat * stat_info) {
        register const char * x0_pathname asm ("x0") = pathname; // first arg
        register struct stat * x1_stat_info asm ("x1") = stat_info;  // second arg
        register int x16_syscall_number asm ("x16") = syscall_number; // special syscall number store to x16
    
        register int x4_ret asm("x4") = -1; // store result
    
        __asm__ volatile(
             "svc #0x80\n"
             "mov x4, x0\n"
            : "=r"(x4_ret)
            : "r"(x0_pathname), "r"(x1_stat_info), "r"(x16_syscall_number)
    //         : "x0", "x1", "x4", "x16"
        );
        return x4_ret;
    }
    
    • 调用内联汇编
    // normal ObjC code
    #import <sys/syscall.h>
    
    ...
        int openResult = -1;
        struct stat stat_info;
        const char * filePathStr = [filePath UTF8String];
    ...
      // call inline asm function
        openResult = svc_0x80_syscall(SYS_stat64, filePathStr, &stat_info);
    

    文档

    【讨论】:

    • 您的 GNU C Basic asm 示例都是不安全的,除非在 __attribute__((naked)) 函数中或在全局范围内(如果您要定义整个函数而不是使用单独的 .S 文件)。绝不应在该上下文之外使用它;始终使用扩展 asm,这样您就可以决定是否要使用 "dsb ish" 使用 "memory" clobber,而不是将其隐含在某些编译器上而不是其他编译器上。请参阅gcc.gnu.org/wiki/ConvertBasicAsmToExtended 了解其可怕的原因。
    • x86 AT&T 语法在 iphone 问答中似乎是一个奇怪的选择。 (另外,$label(%edx,%ebx,$4) 引用符号 $label,而不是 label;也许您将它与 AT&T 语法混为一谈以获取直接操作数?但这是在 Basic Asm 部分,所以它应该被删除。)在 Extended Asm部分,您仍在使用 AT&T 语法来处理 x86 / x86-64,尽管至少它看起来没有错误。但由于 AT&T 的源/目标顺序与 AArch64 程序集相反,这可能会造成混淆。
    • 你稍后说“我的示例代码”;您是说您从其他地方引用了 x86 示例吗?语法的 BNF 是从 GCC 手册中复制的,这很好,但如果您要复制示例,您可能应该引用它们。 (但同样,由于它们是 x86 示例,您应该删除它们。)事实上,它们都是您的示例,通过选择将它们包含在您的答案中。
    • 不幸的是,您使用 svc 0x80 的 AArch64 示例忘记在您编写的硬寄存器上声明 clobbers。请注意,您的函数甚至是 always_inline,因此即使在 -O0 处,这也会导致损坏,而不仅仅是启用优化。 (不是这样就可以了;即使noinline 也不能证明它是合理的,因为编译器可以选择 x0 作为输入,因此您在阅读之前覆盖它。)。
    • 另外,如果你的 asm 模板以 mov 开头和/或结尾,你通常做错了(或效率低下):相反,告诉编译器你想要你的值在哪个寄存器中。例如使用register const char *path __asm__("x0") = pathname 进行"r" 约束选择x0。请参阅stackoverflow.com/tags/inline-assembly/info 中的链接。这具有另一个优点,即编译器知道这些值之后仍在 regs 中。你可能应该使用"r"(SYS_stat64) 约束作为电话号码,如果 iPhone 有,则使用来自&lt;sys/syscall.h&gt; 的常量(GNU 和 BSD 可以)。
    猜你喜欢
    • 1970-01-01
    • 2011-02-19
    • 2012-11-17
    • 1970-01-01
    • 2012-10-20
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    相关资源
    最近更新 更多