Home | History | Annotate | Download | only in aarch32
      1 Getting Started with VIXL for AArch32
      2 =====================================
      3 
      4 
      5 This guide will show you how to use the VIXL framework for AArch32. We will see
      6 how to set up the VIXL assembler and generate some code. We will also go into
      7 details on a few useful features provided by VIXL and see how to run the
      8 generated code.
      9 
     10 The source code of the example developed in this guide can be found in the
     11 `examples/aarch32` directory (`examples/aarch32/getting-started.cc`).
     12 
     13 
     14 Creating the macro assembler.
     15 -----------------------------
     16 
     17 First of all you need to make sure that the header files for the assembler are
     18 included. You should have the following lines at the beginning of your source
     19 file:
     20 
     21     // You may use <cstdint> if using C++11 or later.
     22     extern "C" {
     23     #include <stdint.h>
     24     }
     25 
     26     #include <cstdio>
     27     #include <string>
     28     #include "aarch32/constants-aarch32.h"
     29     #include "aarch32/instructions-aarch32.h"
     30     #include "aarch32/macro-assembler-aarch32.h"
     31 
     32 In our case, those files are included by "examples.h".
     33 
     34 All VIXL components are declared in the `vixl::aarch32` namespace, so let's add
     35 this to the beginning of the file for convenience (once again, done in
     36 "examples.h"):
     37 
     38     using namespace vixl::aarch32;
     39 
     40 Now we are ready to create and initialise the different components.
     41 
     42 First of all we need to create a macro assembler object.
     43 
     44     MacroAssembler masm;
     45 
     46 
     47 Generating some code.
     48 ---------------------
     49 
     50 We are now ready to generate some code. The macro assembler provides methods
     51 for all the instructions that you can use. As it's a macro assembler,
     52 the instructions that you tell it to generate may not directly map to a single
     53 hardware instruction. Instead, it can produce a short sequence of instructions
     54 that has the same effect.
     55 
     56 Before looking at how to generate some code, let's introduce a simple but handy
     57 macro:
     58 
     59     #define __ masm->
     60 
     61 It allows us to write `__ Mov(r0, 42);` instead of `masm->Mov(r0, 42);` to
     62 generate code.
     63 
     64 Now we are going to write a C++ function to generate our first assembly
     65 code fragment.
     66 
     67     void GenerateDemo(MacroAssembler *masm) {
     68       __ Ldr(r1, 0x12345678);
     69       __ And(r0, r0, r1);
     70       __ Bx(lr);
     71     }
     72 
     73 The generated code corresponds to a function with the following C prototype:
     74 
     75     uint32_t demo(uint32_t x);
     76 
     77 This function doesn't perform any useful operation. It loads the value
     78 0x12345678 into r1 and performs a bitwise `and` operation with
     79 the function's argument (stored in r0). The result of this `and` operation
     80 is returned by the function in r0.
     81 
     82 Now in our program main function, we only need to create a label to represent
     83 the entry point of the assembly function and to call `GenerateDemo` to
     84 generate the code.
     85 
     86     Label demo;
     87     masm.Bind(&demo);
     88     GenerateDemo(&masm);
     89     masm.Finalize();
     90 
     91 Now we are going to learn a bit more on a couple of interesting VIXL features
     92 which are used in this example.
     93 
     94 ### Label
     95 
     96 VIXL's assembler provides a mechanism to represent labels with `Label` objects.
     97 They are easy to use: simply create the C++ object and bind it to a location in
     98 the generated instruction stream.
     99 
    100 Creating a label is easy, since you only need to define the variable and bind it
    101 to a location using the macro assembler.
    102 
    103     Label my_label;      // Create the label object.
    104     __ Bind(&my_label);  // Bind it to the current location.
    105 
    106 The target of a branch using a label will be the address to which it has been
    107 bound. For example, let's consider the following code fragment:
    108 
    109     Label foo;
    110 
    111     __ B(&foo);     // Branch to foo.
    112     __ Mov(r0, 42);
    113     __ Bind(&foo);  // Actual address of foo is here.
    114     __ Mov(r1, 0xc001);
    115 
    116 If we run this code fragment the `Mov(r0, 42)` will never be executed since
    117 the first thing this code does is to jump to `foo`, which correspond to the
    118 `Mov(r1, 0xc001)` instruction.
    119 
    120 When working with labels you need to know that they are only to be used for
    121 local branches, and should be passed around with care. The major reason is
    122 that they cannot safely be passed or returned by value because this can trigger
    123 multiple constructor and destructor calls. The destructor has assertions
    124 to check that we don't try to branch to a label that hasn't been bound.
    125 
    126 
    127 ### Literal Pool
    128 
    129 On AArch32 instructions are 16 or 32 bits long, thus immediate values encoded in
    130 the instructions have limited size. If you want to load a constant bigger than
    131 this limit you have two possibilities:
    132 
    133 1. Use multiple instructions to load the constant in multiple steps. This
    134   solution is already handled in VIXL. For instance you can write:
    135 
    136   `__ Mov(r0, 0x12345678);`
    137 
    138   The previous instruction would not be legal since the immediate value is too
    139   big. However, VIXL's macro assembler will automatically rewrite this line into
    140   multiple instructions efficiently generate the value, ultimately setting 'r0'
    141   with the correct value.
    142 
    143 
    144 2. Store the constant in memory and load this value from the memory. The value
    145   needs to be written near the code that will load it since we use a PC-relative
    146   offset to indicate the address of this value. This solution has the advantage
    147   of making the value easily modifiable at run-time; since it does not reside
    148   in the instruction stream, it doesn't require cache maintenance when updated.
    149 
    150   VIXL also provides a way to do this:
    151 
    152   `__ Ldr(r0, 0x12345678);`
    153 
    154   The assembler will store the immediate value in a "literal pool", a set of
    155   constants embedded in the code. VIXL will emit the literal pool when needed.
    156 
    157   The literal pool is emitted regularly, such that they are within range of the
    158   instructions that refer to it. However, you can force the literal pool to be
    159   emitted using `masm.EmitLiteralPool()`. It generates a branch to skip the
    160   pool.
    161 
    162 
    163 Running the code.
    164 -----------------
    165 
    166 We first need to run a few operations to get executable code. The
    167 `ExecutableMemory` helper takes care of it:
    168 
    169     byte* code = masm.GetBuffer().GetBuffer();
    170     uint32_t code_size = masm.GetBuffer().GetSizeInBytes();
    171     ExecutableMemory memory(code, code_size);
    172 
    173 Then we compute a pointer to the function we just generated and copy:
    174 
    175     uint32_t (*demo_function)(uint32_t) =
    176         memory.GetOffsetAddress<uint32_t (*)(uint32_t)>(0);
    177 
    178 Now, we can call this function pointer exactly as if it were a pointer on a C
    179 function:
    180 
    181     uint32_t input_value = 0x89abcdef;
    182     uint32_t output_value = (*demo_function)(input_value);
    183 
    184 A little trace:
    185 
    186     printf("native: abs(%08x) = %08x\n", input_value, output_value);
    187 
    188 
    189 The example shown in this tutorial is very simple, because the goal was to
    190 demonstrate the basics of the VIXL framework. There are more complex code
    191 examples in the VIXL `examples/aarch32` directory showing more features of both the
    192 macro assembler and the AArch32 architecture.
    193 
    194 Disassembling the generated code.
    195 ---------------------------------
    196 
    197 Once you have generated something with the macro-assembler, you may want to
    198 disassemble it.
    199 
    200 First, you must include iostream.
    201 
    202     #include <iostream>
    203 
    204 And the disassembler header file:
    205 
    206     #include "aarch32/disasm-aarch32.h"
    207 
    208 Then you have to define the pc used to disassemble (the one which is used to
    209 display the addresses not the location of the instructions):
    210 
    211     uint32_t display_pc = 0x1000;
    212 
    213 Or, if you running on a 32 bit host, you can use the real address:
    214 
    215     uint32_t display_pc = static_cast<uintptr_t>(masm.GetBuffer().GetBuffer());
    216 
    217 Then you can disassemble the macro assembler's buffer:
    218 
    219     PrintDisassembler disasm(std::cout, display_pc);
    220     disasm.DisassembleA32Buffer(
    221         masm.GetBuffer().GetOffsetAddress<uint32_t*>(0), masm.GetCursorOffset());
    222 
    223 If you generated T32 code instead of A32 code, you must use
    224 DisassembleT32Buffer. Warning: if your buffer contains some data or contains
    225 mixed T32 and A32 code, the result won't be accurate (everything will be
    226 disassembled as T32 or A32 code).
    227 
    228 Example of disassembly:
    229 
    230     0x00001000  e30f0fff	mov r0, #65535
    231     0x00001004  e34f0fff	movt r0, #65535
    232     0x00001008  e3041567	mov r1, #17767
    233     0x0000100c  e3401123	movt r1, #291
    234     0x00001010  e3a02000	mov r2, #0
    235     0x00001014  e7c2001f	bfc r0, #0, #3
    236     0x00001018  e7d4081f	bfc r0, #16, #5
    237     0x0000101c  e7c72011	bfi r2, r1, #0, #8
    238     0x00001020  e7df2811	bfi r2, r1, #16, #16
    239     0x00001024  e1000070	hlt 0
    240