How to write assembly code for the iPhone
shervinemami.info
shervinemami.info
Btw: there is zero support from Apple, so your only chance is to find this kind of blog posts, and they are very few. Bookmark it now if you may need it someday.
I'm pretty sure ldrneb was never a valid instruction; gnu as tended to be more flexible than ARM's specification of the assembly language. Some of this flexibility used to be allowed by ARM (maybe), the rest was depreciated with UAL and llvm only supports ARM's UAL syntax. You can get this behaviour from GNU as via .syntax unified (which you really ought to be using, since it makes it really easy to support assembling to both ARM and Thumb-2)
[1] https://developer.apple.com/library/mac/#documentation/Devel...
Unfortunately this works different from the assembler from linux (Android), so I need to keep two different macros. No matter what, this is still better than nothing!
The iOS toolchain applies the C preprocessor to assembly sources by default; it's been a while since I've used the mainline gnu tools, but I think it is automatically applied to .S (capital S) files by default there.
If you have more questions or issues with the iOS toolchain, please file bugs and/or post your question to the devforums. There are plenty of people who use assembler everyday who will be happy to help out.
And just to echo grandparent: the unified assembler language has been standard on ARM for several years now; pre-unified mnemonics like strneb are deprecated.
>If you have more questions or issues with the iOS toolchain, please file bugs and/or post your question to the devforums. There are plenty of people who use assembler everyday who will be happy to help out.
Thanks. Didn't know that..
>And just to echo grandparent: the unified assembler language has been standard on ARM for several years now; pre-unified mnemonics like strneb are deprecated.
I just spent a few hours cleaning up the code to be UAL compatible. Android NDK seems to support both ".syntax unified" and ".syntax divided", but iOS assembler from xcode4.5 can only support unified. Besides the conditional instructions, with UAL enabled you can't assemble the following instruction with Android NDK's assembler:
orr r1,r0,lsl#8
instead, you must give the dest reg explicitly:
orr r1,r1,r0,lsl#8
My "work around", such as it is, is that the C standard says that # shall be followed by a macro parameter; if it isn't (as will be the case with # in ARM assembly) the behavior is undefined by the standard, and it happens that LLVM does the "right thing" (from the perspective of someone who wants to get things done without a lot of hassle) and simply passes the # through unchanged.
This is obviously imperfect, but it works for my purposes. It may not be sufficient for your needs.
The inability of (some builds of?) gas to support implicit sources under .syntax unified has also annoyed me.
(One of the most irritating things I had to do while supporting all of the initial iPhone jailbreak efforts was to reimplement a ton of gas macro features from later versions of the assembler so I could compile the "normal programs" that people expected to work on this system.)
To the extent to which that is then some kind of veiled challenge or poke (as I'm having a very difficult time understanding why you are telling me to do something now when I've been talking about work I did five years ago, although work that I still rely on), I will then make the counter-poke: GCC is open source, as is gas; it is certainly the case that "patches and bug reports are always welcome". Just because something exists does not mean it is entitled to "patches and bug reports" when there are better alternatives. I personally have no real interest in being able to use Apple's off-the-shelf toolchain, nor do I appreciate their reasons for forking so far.
A key problem here, of course, is that many people in the Apple development community have a strong negative impression of both GCC and GAS; but, as far as I can tell, this is almost entirely the fault (and probably strategic plan) of Apple, who have been working with a 5-year old version of GCC hooked up to a 20-year old version of GAS. It is incredibly painful for me to see all of this great work and effort being ignored and rewritten from scratch by a new generation of people whom Apple have brainwashed into thinking this is then a technical issue and not a licensing one.
Regardless, in my attempts (two weeks ago) to use LLVM MC (disassembler), I found a handful of issues that I had to fix (on SVN head) to get it to even generate correct disassembly (although one or two of the bugs were in the table definitions and should also affect assembly) on the first project I tried to disassemble with it: I thought it would even be a simple case (a bootrom, which would thereby have no relocations or anything particularly tricky to understand or decode: just some instructions).
The result of that is, from being on the IRC channel (where after having a vague discussion about some MC API and usage issues, I attempted to bring up some of these bugs), I did and still do not get the impression that anyone there really seems to care about these kinds of encoding issues, so the bugs I found are likely just going to rot.
Honestly, I do not feel even remotely bad about this, because binutils (which I have already recoded my project to use instead) does not have any of these issues, and is also open source. I really believe that Apple's forking of the community efforts are harmful to the cause, and I would frankly rather not encourage their behavior: if they want their toolchain to work well, and they want my help to make that happen, they are going to need to accept the licensing requirements of GCC; otherwise, I'm quite happy to watch them have to do all of the reimplementation work entirely on their own.
(Some might now point out that binutils doesn't provide all of the same data that LLVM theoretically provides, but the way LLVM provides it is actually sufficiently useless--in addition to being incorrect--that I do not mind. The LLVM API, especially at the MC level, is highly overrated: it was seriously sufficiently bad that I ended up in a situation where parsing the string output it provides was more useful than attempting to extract meaning from their MCInst objects. I could find the attitude "stop using that thing that works and instead contribute patches to LLVM" defendable if LLVM were better designed, but it sadly simply is not; it is slightly easier to use as a library to do backend compilation, and it has better error reporting, but both of these would have been simple and welcome contributions to gcc.)
http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html
http://blog.llvm.org/2010/04/arm-advanced-simd-neon-intrinsi...
That is probably because there are fewer instructions to memorize.
If anyone's looking to learn, MIPS is really easy to pick up. There's a good simulator (SPIM[1]) with terminal and GUI interfaces and lots of tutorials, as it's used in a lot of undergrad computer architecture courses.
"x86" instructions now number in the hundreds. Almost any RISC ISA will max at 30% of that, with less than half of the addressing modes. "Easy" is an adjective, but "easier" is an ordering relation: ARM is easier than x86.
I find confusing the three parameter mode of many ARM instructions and the possibility to have multiple execution modes.
I did Z80, x86, 6800 and MIPS programming back in the day.
Conservatively (relative to x86 where I'd imagine everyone counts pavgb and pavgw as separate instructions), ARM has well over 300 instructions. Include significantly different permutations of instructions, and you're easily over 500, and probably outnumbers x86.
Even if you discount vector and floating point, ARM still has around a hundred distinct instructions.
x86 does have somewhat more instruction names, but not dramatically more (and the blowup is largely because of differences in naming conventions; Intel, for instance uses different names for [vector|scalar][single|double]float operations, whereas they are all the same name on ARM).
What makes ARM nicer (and it is somewhat nicer, in my experience as someone who spends hundreds of hours writing assembly code for both architectures every year) is:
1. non-destructive operations (finally coming to Intel too!)
2. better orthogonality, fewer weird holes in the ISA (especially in the vector ops)
3. no piecemeal vector extensions (all the various extensions that may or may not be available on x86 are madness).
When you really get down to it, though, none of these make a huge difference; they're just niceties.
Also, there is the x86 thing (that, IIRC, ARM and Z80 have, too) to give part of a register an entirely unrelated name (upper half of register X is called A, lower half B). That is avoidable complexity, if one is willing to give up backwards compatibility of source code.
- A compiler is expected to produce reasonably fast code in microseconds.
- An assembly programmer is expected to produce the fastest code possible in hours or days or weeks.
Given hours or days, and development work focused on such a task, compilers would be able to compete with good assembly programmers; it simply hasn't been the focus of much compiler development, because most users don't want to wait three days for their code to compile.
What's remarkable is that compilers are able to fairly consistently beat assembly programmers of average skill, while delivering results thousands of times faster.