Arm Assembly "Retne" Instruction

ARM assembly retne instruction

The architectural assembly language is one thing, real world code is another. Once assembler pseudo-ops and macros come into play, a familiarity with both the toolchain and the codebase in question helps a lot. Linux is particularly nasty as much of the assembly source contains multiple layers of both assembler macros and CPP macros. If you know what to look for, and follow the header trail to arch/arm/include/asm/assembler.h, you eventually find this complicated beast:

.irp    c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
.macro ret\c, reg
#if __LINUX_ARM_ARCH__ < 6
mov\c pc, \reg
#else
.ifeqs "\reg", "lr"
bx\c \reg
.else
mov\c pc, \reg
.endif
#endif
.endm
.endr

The purpose of this is to emit the architecturally-preferred return instruction for the benefit of microarchitectures with a return stack, whilst allowing the same code to still compile for older architectures.

Clarity About TST Instruction - ARM Assembly

What is an easier to understand definition of tst and what is the equivalent to it in C?

Some background

There is no equivalent in C because higher-level languages work differently than a CPU with "status registers" (such as ARM or x86):

In high-level languages like C or C++, conditional code execution can be done directly:

if(a < b) ...

On a CPU with a "status register", conditional code execution is done in two steps:

  • In the first step, you perform some calculation (such as a-b).

    In the so-called "status register" the CPU stores some "relevant" information (e.g. the sign) about the result.
  • In the second step, the actual conditional code execution is done.

    This can only be done depending on the information in the "status register".

A simplified example:

The operation if(a < b) ... could be performed the following way on a CPU with a "status register":

/* Subtract b from a */
c = a - b;
/* (a < b) means that (a - b) is negative */
if(status.last_result_was_negative) ...

... however, the result of the operation (c in the example) is not needed.

The TST and CMP instructions

To perform an if(...) operation, two operations are often needed:

  • A subtraction:

    it is needed for ==, <, >, <=, >= and !=.
  • An AND operation:

    it is needed to check if some bit(s) in a value is (are) set:

    if(a & 0x8000) ...

... and in both cases, the result of the operation (the difference or the result of the AND operation) is not needed.

For this reason, there are two instructions (CMP and TST) that perform an operation (CMP performs a subtraction and TST performs an AND operation) but discard the result:

The TST operation performs an AND operation, sets the information in the "status register" according to the result but it discards the actual result.

This makes sense in lines like if(a & 0xF000) ... where you are only interested in that the "status register" holds the information if the result of the operation a & 0xF000 was zero or not, but you are not interested in the actual result of a & 0xF000.

if(valRead & 0x80000000 != 0){} 

You need brackets:

if((valRead & 0x80000000) != 0){} 

Otherwise the compiler understands:

if(valRead & (0x80000000 != 0)){} 

... which is the same as:

if((valRead & 1) != 0){} 

Encoding ARM assembly instruction to ARM machine language

Since you did finally solve this mostly on your own:

so.s

CMN r9,r10,ROR r11

assemble into machine code in an object file and then disassemble that

arm-none-eabi-as so.s -o so.o
arm-none-objdump -d so.o

so.o: file format elf32-littlearm

Disassembly of section .text:

00000000 <.text>:
0: e1790b7a cmn r9, r10, ror r11

From that

CMN r9,r10,ROR r11
.inst 0xe1790b7a

Disassembly of section .text:

00000000 <.text>:
0: e1790b7a cmn r9, r10, ror r11
4: e1790b7a cmn r9, r10, ror r11

from the arm documentation.

CMN (register-shifted register)
CMN<c> <Rn>, <Rm>, <type> <Rs>
[cond]00010111[rn]0000[rs]0[type]1[rm]

rn is r9 so 1001
rm is r10 so 1010
rs is r11 so 1011

[cond]00010111[1001]0000[1011]0[type]1[1010]

condition is always so 1110
type is ror so 11

[1110]00010111[1001]0000[1011]0[11]1[1010]
1110000101111001000010110111010
1110 0001 0111 1001 0000 1011 0111 1010
0xE1790B7A

as fast as you can type/write it down you can encode it.

Only if doing it by hand and using the tool doesn't match then you need to figure out why. Rare occasions it is the documentation see if you can find an older newer one from the processor folks, not some third party thing. Or if it doesn't then match perhaps you are looking at the wrong instruction description see how the disassembly compares to the documentation to figure out the encoding. (or you are using the tool wrong in some way or wrong tool). Only if it does not match at all and you can't figure it out does it become a Stack Overflow question, well first a support question to the chip/core tech support, then after that a place like here.

ARM SUB Instruction Operands

The 30 is a rotate right operation on the 65

Rotating right 30 bits is the same as rotating left 2 bitswhich is the same as a multiply by 4. 65 * 4 = 260

So this subtracts 260 from the stack pointer.

What is an early register in ARM?

Consider this example code:

LDR R3, [R0,#0x04]
CMP R3, R2

now in this case as load instruction takes some clock cycles to process and the value is not immediately available to compare instruction. In this case the core will stall until the +k cycles have elapsed since we are using R3 earlier before the result is actually written to it.



Related Topics



Leave a reply



Submit