7.1.3. Restrictions on inline assembly operations

There are a number of restrictions on the operations that can be performed in inline assembly code. These restrictions provide a measure of safety, and ensure that the assumptions in compiled C and C++ code are not violated in the assembled assembly code.

Miscellaneous restrictions

The inline assembler has the following restrictions:

  • The inline assembler is a high-level assembler, and the code it generates might not always be exactly what you write. Do not use it to generate more efficient code than the compiler generates. Use embedded assembler or the ARM assembler armasm for this purpose.

  • Some low-level features that are available in the ARM assembler armasm, such as branching and writing to PC, are not supported.

  • Label expressions are not supported.

  • You cannot get the address of the current instruction using dot notation (.) or {PC}.

  • The & operator cannot be used to denote hexadecimal constants. Use the 0x prefix instead. For example:

    __asm { AND x, y, 0xF00 }
    
  • The notation to specify the actual rotation of an 8-bit constant is not available in inline assembly language. This means that where an 8-bit shifted constant is used, the C flag must be regarded as corrupted if the NZCV flags are updated.

  • You must not modify the stack. This is not necessary because the compiler automatically stacks and restores any working registers as required. The compiler does not permit you to explicitly stack and restore work registers.

Registers

Registers such as r0-r3, sp, lr, and the NZCV flags in the CPSR must be used with caution. If you use C or C++ expressions, these might be used as temporary registers and NZCV flags might be corrupted by the compiler when evaluating the expression. See Virtual registers.

The pc, lr, and sp registers cannot be explicitly read or modified using inline assembly code because there is no direct access to any physical registers. However, you can use the following intrinsics described in the Compiler Reference Guide to access these registers:

Processor modes

You can change processor modes or modify coprocessor states, but the compiler does not recognize these changes. If you change processor mode, you must not use C or C++ expressions until you change back to the original mode, otherwise the compiler corrupts the registers for the new processor mode.

Similarly, if you change the state of a floating-point coprocessor by executing floating-point instructions, you must not use floating-point expressions until the original state has been restored.

Thumb instruction set

The inline assembler is not available when compiling C or C++ for Thumb state, and the inline assembler does not assemble Thumb instructions. Instead, the compiler switches to ARM state automatically.

If you want to include inline assembly in a source file that contains code to be compiled for Thumb, enclose the functions containing inline assembler code between #pragma arm and #pragma thumb statements. For example:

...         // Thumb code
#pragma arm // ARM code. Switch code generation to the ARM instruction set so
            // that the inline assembler is available.

int add(int i, int j)
{
    int res;
    __asm
    {
        ADD   res, i, j   // add here
    }
    return res;
}
#pragma thumb   // Thumb code. Switch back to the Thumb instruction set.
                // The inline assembler is no longer available.

You must also compile your code using the --apcs /interwork compiler option.

See:

VFP coprocessor

The inline assembler does not provide direct support for VFP instructions. However, you can specify them using the generic coprocessor instructions.

Inline assembly code must not be used to change VFP vector mode. Inline assembly can contain floating-point expression operands that can be evaluated using compiler-generated VFP code. Therefore, it is important that only the compiler modifies the state of the VFP.

Unsupported instructions

The following instructions are not supported in the inline assembler:

  • BKPT , BX , BXJ, and BLX instructions

    Note

    You can insert a BKPT instruction in C and C++ code by using the __breakpoint() intrinsic.

  • LDR Rn, =expression pseudo-instruction. Use MOV Rn, expression instead. (This can generate a load from a literal pool.)

  • LDRT, LDRBT, STRT, and STRBT instructions

  • MUL, MLA, UMULL, UMLAL, SMULL, and SMLAL flag setting instructions

  • MOV or MVN flag-setting instructions where the second operand is a constant

  • user-mode LDM instructions

  • ADR and ADRL pseudo-instructions.

See __breakpoint in the Compiler Reference Guide.

Copyright © 2002-2010 ARM. All rights reserved.ARM DUI 0205J
Non-ConfidentialID101213