Skip to main content
Engineering LibreTexts

7.3: Register Conventions

  • Page ID
    76127
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Assembly languages allows a programmer to do anything. If a programmer chooses to add a string pointer to an instruction, it might be meaningless and total nonsense to do so, but assembly language allows it. Likewise, there is no mechanism to enforce protocols that make sure different parts of a program, which can be developed by different programmers, use the same conventions. This can be particularly problematic. If programmers develop functions using different conventions, the results can range from just not making sense, to catastrophic failures of a program, or even every program in a system. To keep this from happening, all assembly language systems have agreed upon standards that all assembly language programs are expected to follow. Any program that does not following these standards is automatically erroneous, and has problems that are just waiting to become bugs.

    The standards for writing ARM assembly language are in a document called the Procedure Call Standard for Arm Architecture (AAPCS), with the emphasis on the Application Binary Interface (ABI) section of that document. The conventions and overall structure of a function will follow that standard. Using the standards will result in functions that are easier to implement, understand, and maintain, and functions that are more correct than ones that try to implement functions using adhoc, or worse, no standards.

    7.3.1 Register Calling Conventions

    One issue in implementing functions is register conventions. Register conventions define what registers are valid to pass values into a function and valid for returning values from a function. Register conventions also define the behavior of a register across a function call (e.g., is the register value preserved or not across a function call).

    To begin to explain these conventions, the following table lists the 16 registers that a user program has access to in ARM assembly, as well as their usage, and whether or not they are preserved across a function call.

    Register Uses Preserved across function call
    r0 Argument and return value No (Caller preserved)
    r1 Argument and return value No (Caller preserved)
    r2 Argument No (Caller preserved)
    r3 Argument No (Caller preserved)
    r4 General Purpose Yes (Callee preserved)
    r5 General Purpose Yes (Callee preserved)
    r6 General Purpose Yes (Callee preserved)
    r7 General Purpose Yes (Callee preserved)
    r8 General Purpose Yes (Callee preserved)
    r9 Normally General Purpose, but in some versions of the AAPCS it is special use Normally preserved, but see previous column
    r10 General Purpose Yes (Callee preserved)
    r11 General Purpose Yes (Callee preserved)
    r12 Scratch register Yes (Callee preserved)
    r13 Stack Pointer (sp) Yes (Callee preserved)
    r14 Link Register (lr) Yes (Callee preserved)
    r15 Program Counter (pc) No

    For this table, the terms Caller and Callee will be defined using the following code fragment.

    Caller: 
        BL Callee 
        MOV pc, lr 
    Callee: 
        # do something 
        BL Callee
    

    As shown in this fragment, the Caller function is any function calling another function. A Callee function is any function called from another function. Note that the Caller and Callee attributes of the relationship between two functions. Functions can be a Caller in relationship to one function, and a Callee in relationship to another function.

    The registers in ARM all belong to a specific group or have a specific meaning. Registers r13, r14, and r15 are the Stack Pointer (sp), Link Register (lr) and Program Counter (pc), and have been covered in a previous chapter.

    Registers r0-r3 are a group of registers that are used to pass arguments into a function and return values from a function. These registers are not preserved by convention, so they can be used in a function without having to be saved and restored. If they contain values that are needed by the executing function, it is the responsibility of the function to save these values either into preserved registers or stack memory. The standard usage of these registers in this textbook is if the value in the register is meaningful, it should be saved at the start of the function, and that these 4 registers then be used as temporary registers.

    For the purposes of this textbook, registers r4-r12 are group representing general purpose registers. The programmer may safely assume that their values will not be changed as a result of the execution of a Callee function. If a Callee function uses and changes the value in these registers, they must save the original value to the stack when entering the function (in a push operation), and restore the original value when leaving the function (in a pop operation).

    The following program illustrates the use of these registers. In this program, a function called addValue is defined which adds a value passed into the function to a value read in from a user, and returns the sum of the argument and the user entered value.

    main: 
        SUB sp, sp, #4 
        STR lr, [sp, #0] 
        
        MOV r0, #5 
        BL addValue
        MOV r1, r0 
        LDR r0, =output 
        BL printf 
        
        MOV r0, #0 
        LDR lr, [sp, #0] 
        ADD sp, sp, #4 
        MOV pc, lr 
    
    .data 
        output: .asciz "Your answer is %d\n"
        
    .text 
    # function addValue 
    addValue: 
        SUB sp, sp, #8 
        STR lr, [sp,#0] 
        STR r4, [sp, #4] // r4 will be used to save r0, so store the 
                         // original value to stack 
        MOV r4, r0       // Save r0 in r4 
        
        LDR r0, =prompt 
        BL printf 
        LDR r0, =inputFormat 
        LDR r1, =inputNum 
        BL scanf 
        LDR r1, =inputNum 
        LDR r0, [r1, #0] 
        ADD r0, r4 
        
        LDR r4, [sp, #4] 
        LDR lr, [sp, #0] 
        ADD sp, sp, #8 
        MOV pc, lr 
        
    .data 
        inputNum: .word 0 
        prompt: .asciz "Enter input number: " 
        inputFormat: .asciz "%d"
    

    The function addValue in this program is passed a value to add in the r0 register. However, the r0 register is used by the scanf function, and so the value cannot be kept in r0. In this program, the original value r0 (a temporary register) is saved in r4 (a preserved register). Note that r4 is a preserved register, so its value is preserved or maintained across the call to scanf. This is in keeping with our convention that when a value in r0, r1, r2, or r3 is used in the function, the value in that register is saved as soon as the function is entered.

    Note that since r4 is now modified to hold the value originally in r0, the r4 register must be preserved across the call to addValue. Thus, addValue must save r4 to the stack when the function is entered, and then retrieve r4 from the stack when the function returns. This is how the value of a preserved register is maintained across a Callee function and ensures that the value is consistent for the Caller function. A similar process is used in scanf if scanf uses the r4 register, which is why the program can be sure the value of r4 remains unchanged across the call to scanf.


    This page titled 7.3: Register Conventions is shared under a CC BY 4.0 license and was authored, remixed, and/or curated by Charles W. Kann III via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.

    • Was this article helpful?