Home > Software engineering >  ARM64 inline assembly BL BLR BR instructions
ARM64 inline assembly BL BLR BR instructions

Time:10-06

I am in the middle of a problem that I can't seem to figure out. It involves testing the instruction set using c and inline assembly for the arm64. My current problems are with BL, BLR and the BR instructions. My current code looks as follows:

#include <stdio.h>

#define LDRARRAYLENGTH   (4)

__asm __volatile
(
    ".global  myFunction               \n\t"
    ".p2align 4                        \n\t"
    ".type    myFunction,%function     \n\t"
    "myFunction:                       \n\t"
           "mov  x0, #10               \n\t"
           "ret   x30                     \n\t"

);

/*
 *
 */
bool BranchingModes(void)
{
    bool BranchingModesFlag = false;

    //local registers
    int regw0 = 0x00;
    int regw1 = 0x00;
    int regw2 = 0x00;
    int regw3 = 0x00;

    /*
     * Branch with Link branches to a PC-relative offset, setting
     * the register X30 to PC 4. It provides a hint that this is a
     * subroutine call.
     */
    //Clear variables
    regw0 = 0x00;
    regw1 = 0x00;
    regw2 = 0x00;
    regw3 = 0x00;

    __asm __volatile
    (
        "mov  x0, #0                        \n\t"     /* setting up initial variable a */
        "bl myFunction                      \n\t"
        "mov  %[reg1],  x0                  \n\t"
        "nop                                \n\t"

        :[reg0] "=r"(regw0), [reg1] "=r"(regw1)
        :/* This is an empty input operand list */
    );

    /*
     * The BL instruction calls a subroutine called myFunction within the subroutine
     * a variable/register gets a value of 10. When the subroutine returns the
     * the variable/register that got populated in the subroutine gets copied
     * to another variable/register to acknowledge that the subroutine got called
     * and returned using the BL instruction
     */
    if((regw0 == 10) && (regw1 == 10))
    {
        BranchingModesFlag = true;
    }
    else
    {
        BranchingModesFlag = false;
    }

    return BranchingModesFlag;
}

int main()
{
    unsigned int i0 = 0x00;
    unsigned int counter = 0x00;

    BranchingModes();

    for(i0=0x00; i0<=10000;  i0  )
    {
        counter = counter    1;
    }

    return 0;
}

Issue is the code doesn't seem to make to the for loop after BranchingModes function. I know it's the asm section of the BranchingModes function which utilizes the BL instruction. I am not sure what I am doing wrong with that instruction. Am I returning correctly out of the "myFunction" using "ret x30"? I have attempted to use "BR x30" with no success. As BL updates "PC 4" and gets sorted to x30. Similar issue with the BLR instruction, I would appreciate any insight with my issues.

CodePudding user response:

You need to tell the compiler about all registers you clobber, but you don't. The compiler doesn't see your changes to x0 and x30, the latter of which is presumably the reason why your program never returns from BranchingModes.

Haven't tested it, but this should work:

__asm __volatile
(
    "mov  x0, #0                        \n\t"     /* setting up initial variable a */
    "bl myFunction                      \n\t"
    "mov  %[reg1],  x0                  \n\t"
    "nop                                \n\t"

    :[reg0] "=r"(regw0), [reg1] "=r"(regw1)
    :/* This is an empty input operand list */
    :"x0", "x30"
);

Note that this is for calling your specific function. For arbitrary ABI-compliant functions, you'll need to list everything the ABI specifies to be caller-saved as clobber. This will usually be x0 through x18 plus x30, d8 through d15, as well as cc and memory.

  • Related