xref: /aosp_15_r20/external/vixl/doc/aarch64/getting-started-aarch64.md (revision f5c631da2f1efdd72b5fd1e20510e4042af13d77)
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