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