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