[HN Gopher] ARM Assembly: [?] Ways to Return (2017)
___________________________________________________________________
ARM Assembly: [?] Ways to Return (2017)
Author : quantum5
Score : 29 points
Date : 2023-02-09 06:29 UTC (1 days ago)
(HTM) web link (quantum5.ca)
(TXT) w3m dump (quantum5.ca)
| Olipro wrote:
| For older architectures, you really want to use the BX
| instruction unless you can guarantee you're not switching
| execution mode.
|
| as a bit of pointless trivia, MOV PC, PC does not cause an
| infinite loop - it skips the instruction immediately following.
| ksherlock wrote:
| Early versions of ARM (ARM 1/2, optional in 3/4) had a combined
| program counter / status register; since there was only a 26-bit
| address space and instructions are always 32-bit word aligned,
| the top 6 and bottom 2 bits were used for the status register.
|
| So, if you're still developing for an ARM1, not all of these are
| equivalent. MOV/POP/etc will set the PC and the status register;
| B/BL will leave the status register bits alone.
|
| * edit: MOV/MOVS determined if the status bits are written to
| R15.
| garbagecoder wrote:
| fwiw, if you're using ARM assembly on an Apple device there are a
| few differences and one of them is how you pass arguments.
|
| https://developer.apple.com/documentation/xcode/writing-arm6...
| wk_end wrote:
| The article is describing classic ARM. (Modern) Apple devices
| are all ARM64, which doesn't have the PC as a GPR.
|
| The article is also entirely about how the PC is a general-
| purpose register on 32-bit ARM machines. No idea if the 1st gen
| iPhones or whatever used an idiosyncratic calling
| convention...but it's moot in the context of this post, because
| argument passing isn't covered here!
|
| This post really is just about the observation that the PC is a
| GPR implies that there's a bunch of different ways to get data
| into it. It's pretty airy. The author was admittedly a first or
| second year university student at the time, so it's hard to be
| too mad though.
| flykespice wrote:
| The only one getting mad here is you for no reason.
| klodolph wrote:
| Thankfully, PC is no longer a GPR in ARM64. Making PC a GPR seems
| elegant at first glance, but when you actually dive into it and
| see how it affects processor implementations and how it affects
| the code you write, it turns out to be extremely messy and
| inconvenient. Good riddance PC as GPR, don't let the door hit you
| on the way out.
| crest wrote:
| It's neat when writing assembler e.g. add a scaled byte value
| to the PC to implement a jump table or perform a scaled and
| indexed load to the PC. In ARM it also produced a neat short
| and fast function prologue/epilogue. In my opinion the worst
| problem causes are the 1001 and one special cases it adds in an
| optimised out of order implementation. The Thumb interworking
| makes it more worse, but is useful to increase code density in
| ARM v6-M and can even increase performance (per clock) of ARM
| v7-M cores. I don't expect it causes too much problems in
| single-issue in-order implementations like the Cortex M3 and
| M4. I would like to know how much design time and core area is
| spend on this in the M7 and M85 cores.
| Dwedit wrote:
| Method 1 (popping PC off the stack) and Method 3 (mov pc,lr) do
| not work on the earliest ARM processors that support THUMB, as it
| will not switch to THUMB mode without executing a BX instruction.
|
| Checking reference manuals:
|
| ARMV4T (ARM7TDMI/ARM9TDMI): Does NOT switch to THUMB mode
| automatically
|
| ARMV5: Does NOT switch to THUMB mode automatically
|
| ARMV7: Does switch to THUMB mode automatically
| benj111 wrote:
| I thought it switched to thumb based on odd/ evenness.
|
| Plus if you don't want to switch to thumb, this still works?
| pm215 wrote:
| It is based on whether the low bit of the jump target is 0 or
| 1, but the first version of Thumb only did that check-and-
| switch-mode on a small set of jump instructions, not on every
| way you could alter the program counter. For the others you
| got the same behaviour you always had for an attempt to jump
| to an unaligned address, which is to say the low bit was just
| ignored. The compiler had to generate slightly different code
| if you wanted your function to support interworking. In the
| versions of Thumb starting with IIRC Armv5t or maybe v6t2,
| more instructions did the mode switch check, and codegen got
| a bit simpler.
| Dwedit wrote:
| It does work if you intend to stay in ARM mode only, and will
| crash if THUMB-mode code calls the function. ARMV7 will do
| the mode switch automatically and not crash.
| derf_ wrote:
| In 2010, I tried to use callgrind to profile a project on Arm,
| after having used it to great effect on x86, and discovered that
| because of the variety of ways to return (and call!) functions on
| Arm, callgrind was unable to reliably identify function call and
| return sites. It created cycles in the call graph and even failed
| to record a function's self measurements correctly (because it
| could not tell when you left that function).
|
| The problem boiled down to the valgrind frontend code that splits
| things up into basic blocks being incapable of having an
| instruction be both a conditional jump and a function call /
| return at the same time. That never happens on x86, but of course
| this is possible (and totally normal) on 32-bit Arm. Sadly, I ran
| out of time to try to re-architect this code and had to move on
| to other projects.
|
| Over 12 years later, it looks like it never did get fixed:
| https://bugs.kde.org/show_bug.cgi?id=252091
| Dwedit wrote:
| I use stuff like "bxeq lr" all the time. There's your
| conditional return instruction.
| not2b wrote:
| As other commenters have mentioned, exploiting this will confuse
| other tools and debuggers. Also it tends to play havoc with
| branch prediction meaning that there may be performance
| penalties.
___________________________________________________________________
(page generated 2023-02-10 23:01 UTC)