Difference between revisions of "AArch64 Register and Instruction Quick Start"

From CDOT Wiki
Jump to: navigation, search
(Resources)
(35 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Category:Assembler]]
+
[[Category:Assembly Language]]
 +
 
 +
This page contains very basic information on the AArch64 mode of the [[ARMv8]] architecture: the [[Register|register]] layout and naming and the some basic instructions.
 +
 
 
==  Registers ==
 
==  Registers ==
  
Line 5: Line 8:
  
 
The aarch64 registers are named:
 
The aarch64 registers are named:
* r0 through r30 - for 64-bit-wide access
+
* r0 through r30 - to refer generally to the registers
* w0 through w30 - for 32-bit-wide access (same registers - upper 16 bits are cleared on load)
+
* x0 through x30 - for 64-bit-wide access (same registers)
 +
* w0 through w30 - for 32-bit-wide access (same registers - upper 32 bits are either cleared on load or sign-extended (set to the value of the most significant bit of the loaded value)).
  
 
Register '31' is one of two registers depending on the instruction context:
 
Register '31' is one of two registers depending on the instruction context:
 
* For instructions dealing with the stack, it is the stack pointer, named rsp
 
* For instructions dealing with the stack, it is the stack pointer, named rsp
* For all other instructions, it is a "zero" register, which returns 0 when read and discards data when written - written as rzr
+
* For all other instructions, it is a "zero" register, which returns 0 when read and discards data when written - named rzr (xzr, wzr)
  
Usage during syscall/function call:
+
Usage during [[Syscalls|syscall]]/function call:
* '''r0-r7 are used for arguments and return values'''
+
* '''r0-r7 are used for arguments and return values; additional arguments are on the stack'''
 
* '''For syscalls, the syscall number is in r8'''
 
* '''For syscalls, the syscall number is in r8'''
 
* '''r9-r15 are for temporary values (may get trampled)'''
 
* '''r9-r15 are for temporary values (may get trampled)'''
 
* r16-r18 are used for intra-procedure-call and platform values (avoid)
 
* r16-r18 are used for intra-procedure-call and platform values (avoid)
* '''The called routine is expected to save r19-r28'''
+
* '''The called routine is expected to preserve r19-r28 *** These registers are generally safe to use in your program.'''
 
* r29 and r30 are used as the frame register and link register (avoid)
 
* r29 and r30 are used as the frame register and link register (avoid)
  
Line 29: Line 33:
  
 
=== Starter Kit ===
 
=== Starter Kit ===
These instructions are sufficient to complete the [[SPO600 Assembler Lab]]:
+
These instructions are sufficient to complete the [[SPO600 Assembler Lab]]; remember to replace the generic register names with ones that specify width (for example, replace "r0" with "x0" or "w0").
 +
 
 +
add r0,r1,r2      // load r0 with r1+r2
 +
add r0,r1,99      // load r0 with r1+99
 +
adr r0,''label''      // load r0 with the address ''label'' (this actually calculates an address from the [[Register#Program Counter|PC]] plus an offset)
 +
bl ''label''          // branch (with link) to label - this is a procedure / subroutine / function call
 +
br ''label''          // branch to label - this is a goto
 +
br ''register''      // branch to the address in register
 +
b.eq ''label''        // branch to label if equal
 +
b.ne ''label''        // branch to label if not equal
 +
b.lt ''label''        // branch to label if less
 +
b.gt ''label''        // branch to label if greater
 +
cmp r0,r1        // compare register r0 with register r1. The comparison sets flags in the processor status register which affect conditional branches.
 +
cmp r0,99        // compare the number 99 with register r0. The comparison sets flags in the processor status register which affect conditional branches.
 +
ldr r0,[r1,0]    // load register r0 from the address pointed to by (r1 + (0 * ''size'')) where ''size'' is 8 bytes for 64-bit stores, 4 bytes for 32-bit stores
 +
ldr w0,[r1,0]    // like above but reads 32 bits only - note the use of w0 instead of r0 for the source register name
 +
ldrb w0,[r1,0]    // like above but reads 1 byte (8 bits) only - note the use of w0 for the source register name
 +
ldur r0,[r1,0]    // load register r0 from the address pointed to by (r1 + 0) - the mnemonic means "load ''unscaled'' register"
 +
mov r0,r1        // move data from r1 to r0
 +
mov r0,99        // load r0 with 99 (only certain immediate values are possible)
 +
str r0,[r1,0]    // store register r0 to address pointed to by (r1 + (0 * ''size'')) where ''size'' is 8 bytes for 64-bit stores
 +
strb w0,[r1,0]    // like str but writes one byte only - note the use of w0 for the source register name
 +
stur r0,[r1,0]    // store register r0 to the address pointed to by (r1 + 0) - the mnemonic means "store ''unscaled'' register"
 +
svc 0            // perform a syscall
 +
msub r0,r1,r2,r3  // load r0 with r3-(r1*r2) (useful for calculating remainders)
 +
madd r0,r1,r2,r3  // load r0 with r3+(r1*r2)
 +
mul r0,r1,r2      // load r0 with r1*r2 (actually an alias - see ARM ARM)
 +
push r0          // push r0 onto the stack
 +
pop r0            // pop r0 off the stack
 +
udiv r0,r1,r2    // unsigned - divide r1 by r2, places quotient into r0 - remainder is not calculated (use msub)
  
add r0,r1,r2                      // load r0 with r1+r2
+
Note the syntax:
add r0,r1,99                      // load r0 with r1+99
+
* [[Register]] names are not prefixed.
adr r0,''label''                      // load r0 with the address ''label'' (this actually calculates an address from the [[Register#Program Counter|PC]] plus an offset)
+
* [[Immediate Value|Immediate values]] are not prefixed with a character (they may be prefaced with # if desired).
beq ''label''                          // branch to label if equal
+
* Indirect memory access is indicated by [square brackets].
bne ''label''                          // branch to label if not equal
+
* Hexadecimal values are indicated by a 0x prefix.
blt ''label''                          // branch to label if less
+
* Character values are indicated by quotation marks. Escapes (such as '\n') are permitted.
bgt ''label''                          // branch to label if greater
+
* Destinations are given as the first argument (mov r0, r1 moves INTO r0 FROM r1; you can think of this as r0=r1).
cmp r0,r1                          // compare register r0 with register r1
 
cmp r0,99                          // compare the number 99 with register r0
 
ldr r0,[r1,0]                      // load register r0 from the address pointed to by (r1 + (0 * ''size'')) where ''size'' is 8 bytes for 64-bit stores, 4 bytes for 32-bit stores
 
ldr w0,[r1,0]                     // like ldr but reads one byte only - note the use of w0 instead of r0 for the source register name
 
ldur r0,[r1,0]                    // load register r0 from the address pointed to by (r1 + 0) - the mnemonic means "load ''unscaled'' register"
 
mov r0,r1                          // move data from r1 to r0
 
mov r0,99                          // load r0 with 99 (only certain immediate values are possible)
 
str r0,[r1,0]                      // store register r0 to address pointed to by (r1 + (0 * ''size'')) where ''size'' is 8 bytes for 64-bit stores
 
strb w0,[r1,0]                    // like str but writes one byte only - note the use of w0 instead of r0 for the source register name
 
stur r0,[r1,0]                    // store register r0 to the address pointed to by (r1 + 0) - the mnemonic means "store ''unscaled'' register"
 
mov (%r10),%r11                    // move data from address pointed to by r10 to r10
 
msub r0,r1,r2,r3                  // load r0 with r3-(r1*r2) (useful for calculating remainders)
 
madd r0,r1,r2,r3
 
mul r0,r1,r2                      // load r0 with r1*r2 (actually an alias - see ARM ARM)
 
push r0                            // push r0 onto the stack
 
pop r0                            // pop r0 off the stack
 
udiv r0,r1,r2                      // unsigned - divide r1 by r2, places quotient into r0 - remainder is not calculated (use msub)
 
  
== References ==
+
== Resources ==
  
* Instruction Set and Software Developer Manual: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.genc010197a/index.html
+
* ARM Aarch64 documentation
* Procedure call reference: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
+
** [http://developer.arm.com/ ARM Developer Information Centre]
 +
*** [https://developer.arm.com/docs/den0024/latest ARM Cortex-A Series Programmer’s Guide for ARMv8-A]
 +
*** The ''short'' guide to the ARMv8 instruction set: [https://www.element14.com/community/servlet/JiveServlet/previewBody/41836-102-1-229511/ARM.Reference_Manual.pdf ARMv8 Instruction Set Overview] ("ARM ISA Overview")
 +
*** The ''long'' guide to the ARMv8 instruction set: [https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile] ("ARM ARM")
 +
** [https://developer.arm.com/docs/ihi0055/latest/procedure-call-standard-for-the-arm-64-bit-architecture Procedure Call Standard for the ARM 64-bit Architecture (AArch64)]
 +
* GAS Manual -  Using as, The GNU Assembler: https://sourceware.org/binutils/docs/as/

Revision as of 13:57, 13 September 2019


This page contains very basic information on the AArch64 mode of the ARMv8 architecture: the register layout and naming and the some basic instructions.

Registers

General-Purpose Registers

The aarch64 registers are named:

  • r0 through r30 - to refer generally to the registers
  • x0 through x30 - for 64-bit-wide access (same registers)
  • w0 through w30 - for 32-bit-wide access (same registers - upper 32 bits are either cleared on load or sign-extended (set to the value of the most significant bit of the loaded value)).

Register '31' is one of two registers depending on the instruction context:

  • For instructions dealing with the stack, it is the stack pointer, named rsp
  • For all other instructions, it is a "zero" register, which returns 0 when read and discards data when written - named rzr (xzr, wzr)

Usage during syscall/function call:

  • r0-r7 are used for arguments and return values; additional arguments are on the stack
  • For syscalls, the syscall number is in r8
  • r9-r15 are for temporary values (may get trampled)
  • r16-r18 are used for intra-procedure-call and platform values (avoid)
  • The called routine is expected to preserve r19-r28 *** These registers are generally safe to use in your program.
  • r29 and r30 are used as the frame register and link register (avoid)

See the ARM Procedure Call Reference for details.

Floating-Point and SIMD Registers

Aarch64 also defines a set of large registers for floating-point and single-instruction/multiple-data (SIMD) operations. For details, refer to the ARM documentation.

Instructions

Starter Kit

These instructions are sufficient to complete the SPO600 Assembler Lab; remember to replace the generic register names with ones that specify width (for example, replace "r0" with "x0" or "w0").

add r0,r1,r2      // load r0 with r1+r2
add r0,r1,99      // load r0 with r1+99
adr r0,label      // load r0 with the address label (this actually calculates an address from the PC plus an offset)
bl label          // branch (with link) to label - this is a procedure / subroutine / function call
br label          // branch to label - this is a goto
br register       // branch to the address in register
b.eq label        // branch to label if equal
b.ne label        // branch to label if not equal
b.lt label        // branch to label if less
b.gt label        // branch to label if greater
cmp r0,r1         // compare register r0 with register r1. The comparison sets flags in the processor status register which affect conditional branches.
cmp r0,99         // compare the number 99 with register r0. The comparison sets flags in the processor status register which affect conditional branches.
ldr r0,[r1,0]     // load register r0 from the address pointed to by (r1 + (0 * size)) where size is 8 bytes for 64-bit stores, 4 bytes for 32-bit stores
ldr w0,[r1,0]     // like above but reads 32 bits only - note the use of w0 instead of r0 for the source register name
ldrb w0,[r1,0]    // like above but reads 1 byte (8 bits) only - note the use of w0 for the source register name
ldur r0,[r1,0]    // load register r0 from the address pointed to by (r1 + 0) - the mnemonic means "load unscaled register"
mov r0,r1         // move data from r1 to r0
mov r0,99         // load r0 with 99 (only certain immediate values are possible)
str r0,[r1,0]     // store register r0 to address pointed to by (r1 + (0 * size)) where size is 8 bytes for 64-bit stores
strb w0,[r1,0]    // like str but writes one byte only - note the use of w0 for the source register name
stur r0,[r1,0]    // store register r0 to the address pointed to by (r1 + 0) - the mnemonic means "store unscaled register"
svc 0             // perform a syscall
msub r0,r1,r2,r3  // load r0 with r3-(r1*r2) (useful for calculating remainders)
madd r0,r1,r2,r3  // load r0 with r3+(r1*r2)
mul r0,r1,r2      // load r0 with r1*r2 (actually an alias - see ARM ARM)
push r0           // push r0 onto the stack
pop r0            // pop r0 off the stack
udiv r0,r1,r2     // unsigned - divide r1 by r2, places quotient into r0 - remainder is not calculated (use msub)

Note the syntax:

  • Register names are not prefixed.
  • Immediate values are not prefixed with a character (they may be prefaced with # if desired).
  • Indirect memory access is indicated by [square brackets].
  • Hexadecimal values are indicated by a 0x prefix.
  • Character values are indicated by quotation marks. Escapes (such as '\n') are permitted.
  • Destinations are given as the first argument (mov r0, r1 moves INTO r0 FROM r1; you can think of this as r0=r1).

Resources