How do I use the ARM assembler in XCode?

2020-02-29 10:20发布

问题:

Just for educational purposes, I would like to add a function to an existing iPhone app, written in ARM assembly. I don't need a tutorial on ARM assembly in general, because I already read too many of them. I just don't know how to actually run the code!

What I would like to do is something like:

useless.h:

void useless();

useless.s:

useless:
      bx lr

If this also works on the simulator it would be fine... On the simulator, the .s file would not compile, so I should maybe do something like:

useless.s:

#if I_AM_ARM
useless:
      bx lr
#endif

useless.c:

#if !I_AM_ARM
void useless()
{
}
#endif

I know the syntax I use is broken, but how do I write it correctly? (Breaking an app on the simulator just because I want to try some inline assembly is no option...)

The second-best option would be to use inline assembly, but I would strongly prefer non-inline assembly.

Thanks!

Edit: I want to learn ARM assembly, so I would like to find a method to compile ARM assembly code, and to EXECUTE ARM assembly code.

回答1:

I finally found the answer myself. It's actually not that hard. I only solved it for the 32-bit ARM version though.

useless.h:

void useless();

useless.s:

#ifdef __arm__


    .syntax        unified
    .globl         _useless
    .align         2
    .code          16
    .thumb_func    _useless

_useless:
    //.cfi_startproc
    bx    lr
    //.cfi_endproc

// CFI means Call Frame Information
// Optionally. Use for better debug-ability.


#endif

useless.c:

#ifndef __arm__

void useless()
{
}

#endif

Notes:

The CLANG ARM Assembler syntax is a bit different from what you see in example all over the web. Comments start with // and /* multiline comments */ are also supported. It also understands the standard C preprocessor. The function has to be defined as a Thumb function, if you specify an arm function (.code 32) the program will just crash. The line .thumb_func _useless can be ommited and it works still. I have no Idea what it means. If you omit the .code 16 line, the program crashes.

about the #ifdef. For ARMv7, __arm__ is defined. For ARMv8, i.e. the 64bit-variant on the iPhone 5S, __arm__ is not defined, but __arm64__ is defined instead. The above code does not work for the 64bit-ARM-version. Instead, the implementation from useless.c will be used. (I didn't forget ARMv7s, I just don't have a device with that arch in my hands currently, so I cannot test.)



回答2:

The simulator doesn't use arm. you'll have to write x86_64 assembly if you want it to run on the simulator. (probably).



回答3:

The best way to learn is to take a look at actual working examples, see my blog post about ARM iOS timing. This example Xcode project shows how to mix ARM ASM and C impls of a function. There is also a very accurate timing module to run your code N times, because accurate timing is the hard part when it comes to optimizing the code.



回答4:

You can emulate ARM-Ubuntu with QEmu (there are some Windows ports of it, e.g. http://lassauge.free.fr/qemu/ ). If you are on Windows, you may need to emulate x86_64-Ubuntu in the middle. To create an ARM image you can follow the steps from this question: Black screen in QEmu for ARM-Ubuntu (how to get GUI?) (yes, unfortunately, you get no GUI with these steps, just a console to the ARM-Ubuntu machine, and you have to do the steps from Ubuntu). Then you can cross-compile your C++/C/Assembly programs from Windows/Ubuntu host to ARM-Ubuntu target.

clang++.exe -Wall test1.cpp -o test1exe -std=c++14 -Ipath-to-arm-linaro/arm-linux-gnueabihf/include/c++/5.3.1 -Ipath-to-arm-linaro/arm-linux-gnueabihf/include/c++/5.3.1/arm-linux-gnueabihf -ffunction-sections -fdata-sections --sysroot=path-to-arm-linaro/arm-linux-gnueabihf/libc --target=arm-unknown-linux-gnueabihf -Bpath-to-arm-linaro/arm-linux-gnueabihf/bin/

For cross-compilation you would need to download and roll out a toolchain, e.g. gcc-linaro-5.3-2016.02-i686-mingw32_arm-linux-gnueabihf.tar.xz (Windows/MinGW) from https://releases.linaro.org/components/toolchain/binaries/latest-5/arm-linux-gnueabihf/ and replace "path-to-arm-linaro" in the above command with the path to the toolchain.



回答5:

I just started working with iOS. The first thing I tried to do was add asm code to my project and ran into the same problem. The static data is handled slightly differently in 64-bit mode. I discovered how to do it by looking at the assembler output of the compiler. The same .S file will be compiled as both 32 and 64-bit in Xcode, so prepare it like this:

        .globl         _myfunction
        .align         2

        my_constant_data:
              .byte 0,1,2,3,4,5,6,7

    #ifdef __arm__
        .thumb_func    _myfunction 
        .syntax        unified
        .code          16

    //
    // call from C as my myfunction()
    //
    _myfunction:
       ldr r0,=my_constant_data

    < write your thumb-2 code here >
       bx lr

    #else // or you can use #ifdef __arm64__
    //
    // Call from C as myfunction()
    //
    _myfunction:
       adrp x0, my_constant_data@PAGE
       add x0,x0, my_constant_data@PAGEOFF

    < write your Armv8 code here >
       ret

    #endif