PortAsm MOVEM Translation Bug
PortAsm is a software tool, produced by MicroAPL Ltd, that can be used to translate programs from one assembly language to another. At work we have been using the version that translates from Motorola 68k code to PowerPC for the past 7 years. A couple of weeks ago we discovered a bug in our system which I traced back to the PortAsm translation of a MOVEM instruction being unsafe against interrupts. I am publishing the details here because I can find no other mention of this bug out on the web and by doing so I might just save someone a lot of time.
We are using PortAsm version 4.0.24. (This is probably not the latest version but if MicroAPL have fixed this bug in a later version it would have been nice of them to have informed their customers.) The run-time options used were:
target assembler = Microtech Research asmppc
target runtime = EABI
target byte-order = big-endian
The problem only occurs with MOVEM instructions that push two or more registers onto a stack (ie: the index register is predecremented). It doesn't happen with single register MOVEMs and nor does it happen with pops from the stack (ie: with postincrement). The problem, when it occurs, is that the translated code writes to locations on the stack before those locations have been 'allocated' by having the stack pointer moved past them. If an interrupt that also writes to the stack occurs between the writing and the allocating then the written locations will be overwritten. Here are a couple of examples.
The instruction MOVEM.L D0/A0-A2,-(SP) is translated to:
addi RX,a7,(12)
stswi a0,RX,(12)&0x1f
stwu d0,(-16)(a7)
Here the stswi (store string word indexed) instruction writes the contents of registers a0, a1 and a2 to the stack. The stwu (store word with update) instruction writes the contents of register d0 to the stack and simultaneously updates the stack pointer a7 to allocate the locations just written to.
Similarly, the instruction MOVEM.L D0/A3,-(SP) is translated to:
stw a3,(-4)(a7)
stwu d0,(-8)(a7)
Here the stw instruction writes register a3 to the stack and the stwu instruction writes d0 and simultaneously moves the stack pointer.
There is a simple work-around for this problem: split each multi-register predecrement MOVEM into an equivalent sequence of single-register predecrement MOVEMs. Thus the second example would become:
MOVEM.L A3,-(SP)
MOVEM.L D0,-(SP)
which translates to:
stwu a3,(-4)(a7)
stwu d0,(-8)(a7)
This is safe against interrupts because the stack pointer is moved on with each write.
Lest this article should lead you to think otherwise, I should make clear that I think PortAsm is a good robust piece of software and I would certainly recommend its use to anyone who needs to translate Motorola 68k code to run on a PowerPC.
Reader Comments