1Getting Started with VIXL AArch64 2================================= 3 4 5This guide will show you how to use the VIXL framework for AArch64. We will see 6how to set up the VIXL assembler and generate some code. We will also go into 7details on a few useful features provided by VIXL and see how to run the 8generated code in the VIXL simulator. 9 10The source code of the example developed in this guide can be found in the 11`examples/aarch64` directory (`examples/aarch64/getting-started.cc`). 12 13 14Creating the macro assembler and the simulator. 15----------------------------------------------- 16 17First of all you need to make sure that the header files for the assembler and 18the simulator are included. You should have the following lines at the beginning 19of your source file: 20 21 #include "aarch64/simulator-aarch64.h" 22 #include "aarch64/macro-assembler-aarch64.h" 23 24All VIXL components are declared in the `vixl::aarch64` namespace, so let's add 25this to the beginning of the file for convenience: 26 27 using namespace vixl::aarch64; 28 29Creating a macro assembler is as simple as 30 31 MacroAssembler masm; 32 33VIXL's assembler will generate some code at run-time, and this code needs to 34be stored in a buffer. By default the assembler will automatically manage 35the code buffer. However constructors are available that allow manual management 36of the code buffer. 37 38We also need to set up the simulator. The simulator uses a Decoder object to 39read and decode the instructions from the code buffer. We need to create a 40decoder and bind our simulator to this decoder. 41 42 Decoder decoder; 43 Simulator simulator(&decoder); 44 45 46Generating some code. 47--------------------- 48 49We are now ready to generate some code. The macro assembler provides methods 50for all the instructions that you can use. As it's a macro assembler, 51the instructions that you tell it to generate may not directly map to a single 52hardware instruction. Instead, it can produce a short sequence of instructions 53that has the same effect. 54 55For instance, the hardware `add` instruction can only take a 12-bit immediate 56optionally shifted by 12, but the macro assembler can generate one or more 57instructions to handle any 64-bit immediate. For example, `Add(x0, x0, -1)` 58will be turned into `Sub(x0, x0, 1)`. 59 60Before looking at how to generate some code, let's introduce a simple but handy 61macro: 62 63 #define __ masm-> 64 65It allows us to write `__ Mov(x0, 42);` instead of `masm->Mov(x0, 42);` to 66generate code. 67 68Now we are going to write a C++ function to generate our first assembly 69code fragment. 70 71 void GenerateDemoFunction(MacroAssembler *masm) { 72 __ Ldr(x1, 0x1122334455667788); 73 __ And(x0, x0, x1); 74 __ Ret(); 75 } 76 77The generated code corresponds to a function with the following C prototype: 78 79 uint64_t demo_function(uint64_t x); 80 81This function doesn't perform any useful operation. It loads the value 820x1122334455667788 into x1 and performs a bitwise `and` operation with 83the function's argument (stored in x0). The result of this `and` operation 84is returned by the function in x0. 85 86Now in our program main function, we only need to create a label to represent 87the entry point of the assembly function and to call `GenerateDemoFunction` to 88generate the code. 89 90 Label demo_function; 91 masm.Bind(&demo_function); 92 GenerateDemoFunction(&masm); 93 masm.Finalize(); 94 95Now we are going to learn a bit more on a couple of interesting VIXL features 96which are used in this example. 97 98### Label 99 100VIXL's assembler provides a mechanism to represent labels with `Label` objects. 101They are easy to use: simply create the C++ object and bind it to a location in 102the generated instruction stream. 103 104Creating a label is easy, since you only need to define the variable and bind it 105to a location using the macro assembler. 106 107 Label my_label; // Create the label object. 108 __ Bind(&my_label); // Bind it to the current location. 109 110The target of a branch using a label will be the address to which it has been 111bound. For example, let's consider the following code fragment: 112 113 Label foo; 114 115 __ B(&foo); // Branch to foo. 116 __ Mov(x0, 42); 117 __ Bind(&foo); // Actual address of foo is here. 118 __ Mov(x1, 0xc001); 119 120If we run this code fragment the `Mov(x0, 42)` will never be executed since 121the first thing this code does is to jump to `foo`, which correspond to the 122`Mov(x1, 0xc001)` instruction. 123 124When working with labels you need to know that they are only to be used for 125local branches, and should be passed around with care. There are two reasons 126for this: 127 128 - They can't safely be passed or returned by value because this can trigger 129 multiple constructor and destructor calls. The destructor has assertions 130 to check that we don't try to branch to a label that hasn't been bound. 131 132 - The `B` instruction does not branch to labels which are out of range of the 133 branch. The `B` instruction has a range of 2^28 bytes, but other variants 134 (such as conditional or `CBZ`-like branches) have smaller ranges. Confining 135 them to local ranges doesn't mean that we won't hit these limits, but it 136 makes the lifetime of the labels much shorter and eases the debugging of 137 these kinds of issues. 138 139 140### Literal Pool 141 142On ARMv8 instructions are 32 bits long, thus immediate values encoded in the 143instructions have limited size. If you want to load a constant bigger than this 144limit you have two possibilities: 145 1461. Use multiple instructions to load the constant in multiple steps. This 147 solution is already handled in VIXL. For instance you can write: 148 149 `__ Mov(x0, 0x1122334455667788);` 150 151 The previous instruction would not be legal since the immediate value is too 152 big. However, VIXL's macro assembler will automatically rewrite this line into 153 multiple instructions to efficiently generate the value. 154 155 1562. Store the constant in memory and load this value from the memory. The value 157 needs to be written near the code that will load it since we use a PC-relative 158 offset to indicate the address of this value. This solution has the advantage 159 of making the value easily modifiable at run-time; since it does not reside 160 in the instruction stream, it doesn't require cache maintenance when updated. 161 162 VIXL also provides a way to do this: 163 164 `__ Ldr(x0, 0x1122334455667788);` 165 166 The assembler will store the immediate value in a "literal pool", a set of 167 constants embedded in the code. VIXL will emit literal pools after natural 168 breaks in the control flow, such as unconditional branches or return 169 instructions. 170 171 Literal pools are emitted regularly, such that they are within range of the 172 instructions that refer to them. However, you can force a literal pool to be 173 emitted using `masm.EmitLiteralPool()`. 174 175 176Running the code in the simulator. 177---------------------------------- 178 179Now we are going to see how to use the simulator to run the code that we 180generated previously. 181 182Use the simulator to assign a value to the registers. Our previous code example 183uses the register x0 as an input, so let's set the value of this register. 184 185 simulator.WriteXRegister(0, 0x8899aabbccddeeff); 186 187Now we can jump to the "entry" label to execute the code: 188 189 simulator.RunFrom(entry.target()); 190 191When the execution is finished and the simulator returned, you can inspect 192the value of the registers after the execution. For instance: 193 194 printf("x0 = %" PRIx64 "\n", simulator.ReadXRegister(0)); 195 196The example shown in this tutorial is very simple, because the goal was to 197demonstrate the basics of the VIXL framework. There are more complex code 198examples in the VIXL `examples/aarch64` directory showing more features of both the 199macro assembler and the ARMv8 architecture. 200 201 202Extras 203------ 204 205In addition to this document and the [examples](/examples/aarch64), you can find 206documentation and guides on various topics that may be helpful 207[here](/doc/aarch64/topics/index.md). 208