我该如何在iPhone上使用内联汇编进行编程?

30

如何完成?我需要采取哪些步骤,需要考虑哪些陷阱和意外情况?


不错的问题,我非常感兴趣看到回复。 - mdec
5个回答

20

我已经成功实现了这个,感谢在Apple Devforums得到的内部帮助,如果你是一名专注于iPhone开发的开发人员,那么你应该注册。

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

其次,默认情况下,XCode生成的编译目标会针对ARM Thumb指令集进行内联汇编编译,因此usat不能被识别为正确的指令。要解决这个问题,请在目标上执行“获取信息”操作。滚动到“GCC 4.0 - 代码生成”部分,并取消选中“编译为Thumb”。然后,如果将活动SDK设置为“设备”,则以下代码片段将正常编译。

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


2
我认为你的意思是使用__asm__()而不是简单的asm()。 - Quinn Taylor
为什么 iPhone 模拟器无法运行?是因为模拟器上没有汇编工作,还是因为你必须有一组不同的汇编指令,因为它正在 i386 上运行? - Roberto
1
@Roberto:你说对了。模拟器是在x86上运行的,所以你无法运行ARM汇编。它只是无法编译。 - Dietrich Epp

12

我写了相当多的ARM Cortex-A8汇编代码。iPhone上的CPU是ARM11(据我所知),因此核心指令集是相同的。

你具体需要什么?如果你想要,我可以给你一些例子。


编辑:

我刚刚发现,在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;
}

1
我无法编译这个程序。我一直在尝试使用苹果的XCode。默认情况下,编译器实际上设置为GCC 4。如果我使用该编译器进行编译,则会抱怨出现无效指令'usat',如果我将其设置为使用llvm-gcc,则会抱怨出现无效架构“armv6”。 - Hans Sjunnesson
尝试使用gcc -O3 -march=armv6 test.c。 - Nils Pipenbrinck
这个可以毫无问题地使用工具链进行编译。我很想听一些关于有用的内联汇编的抱怨! - Max Stewart
@Max Stewart 如果你能详细说明一下你是如何通过XCode编译上面的示例,那就太棒了。我没有花太多时间去尝试,但是我没有成功地让它正常工作。 - Hans Sjunnesson
嗨,汉斯,我实际上正在使用Linux上的开放式工具链进行开发 - 我还没有使用XCode的经验,所以不太清楚你应该从哪里开始。 - Max Stewart
显示剩余3条评论

2
寄存器也可以在内联汇编中被显式使用。
void foo(void) {
#if TARGET_CPU_ARM64
    __asm ("sub        sp, sp, #0x60");
    __asm ("str        x29, [sp, #0x50]");
#endif
}

0

推荐在不需要大量浮点运算的应用程序中使用Thumb。Thumb可以使代码大小更小,也可以使代码执行更快。

因此,您应该只在像3D游戏这样的应用程序中关闭Thumb...


3
通常情况下,使用Thumb指令集比使用ARM指令集慢得多。按照一般经验(无恶意),你可以获得1/3的代码大小优势,但会损失1/3的速度。请参阅例如http://www.arm.com/pdfs/Thumb-2CoreTechnologyWhitepaper-Final4.pdf。 - gc.

-1

背景

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

iPhone上的内联汇编

asm关键字

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

asm语法

据我所知,有许多asm语法

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

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

GNU/UNIX语法

基本汇编

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

扩展汇编

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

我的示例代码

  • 环境
    • 开发环境
      • macOS
        • IDE:XCode
          • 编译器:clang
    • 运行环境
      • iOS - iPhone
        • 硬件架构:ARM64

使用扩展汇编内联调用svc 0x80来支持ARM64

  • 在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基本汇编示例都是不安全的,除非在__attribute__((naked))函数中或者在全局范围内定义整个函数而不是使用单独的.S文件。它永远不应该在那种情况之外使用;始终使用扩展汇编,这样您就可以决定是否要在您的"dsb ish"中使用"memory"清除,而不是在某些编译器上隐含地使用,在其他编译器上则不是。请参见https://gcc.gnu.org/wiki/ConvertBasicAsmToExtended,了解为什么这很糟糕。 - Peter Cordes
你后来说“我的示例代码”;你是在说你从别处引用了x86的示例吗?语法的BNF是从GCC手册中复制的,这很好,但如果你要复制示例,你应该引用它们。(但是,由于它们是x86示例,所以你应该将它们删除。)现在,它们都是你的示例,因为你选择以这种方式包含它们在你的答案中。 - Peter Cordes
@PeterCordes 总是返回 -1,这里对于 svc 0x80 syscall检查打开文件 是特殊的。我稍后会进行测试,然后更新代码以不在一般情况下使用 -1 - crifan
你可以并且应该编写调用者来检查 != 0 而不是 == -1,特别是如果它们被编写为使用这个内联汇编包装器而不设置 errno - Peter Cordes
不清楚为什么stat系统调用是其中的一部分,而不是通过内联汇编执行open系统调用。我不了解iOS具体情况,但在POSIX操作系统下,您无需先进行stat操作。如果您想知道文件大小,应该在文件描述符已经打开后使用fstat - Peter Cordes
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接