7 .. index:: Inline Assembler
9 If you need to write low-level software that interacts directly
10 with the hardware, Ada provides two ways to incorporate assembly
11 language code into your program. First, you can import and invoke
12 external routines written in assembly language, an Ada feature fully
13 supported by GNAT. However, for small sections of code it may be simpler
14 or more efficient to include assembly language statements directly
15 in your Ada source program, using the facilities of the implementation-defined
16 package `System.Machine_Code`, which incorporates the gcc
17 Inline Assembler. The Inline Assembler approach offers a number of advantages,
18 including the following:
20 * No need to use non-Ada tools
21 * Consistent interface over different targets
22 * Automatic usage of the proper calling conventions
23 * Access to Ada constants and variables
24 * Definition of intrinsic routines
25 * Possibility of inlining a subprogram comprising assembler code
26 * Code optimizer can take Inline Assembler code into account
28 This appendix presents a series of examples to show you how to use
29 the Inline Assembler. Although it focuses on the Intel x86,
30 the general approach applies also to other processors.
31 It is assumed that you are familiar with Ada
32 and with assembly language programming.
34 .. _Basic_Assembler_Syntax:
36 Basic Assembler Syntax
37 ======================
39 The assembler used by GNAT and gcc is based not on the Intel assembly
40 language, but rather on a language that descends from the AT&T Unix
41 assembler *as* (and which is often referred to as 'AT&T syntax').
42 The following table summarizes the main features of *as* syntax
43 and points out the differences from the Intel conventions.
44 See the gcc *as* and *gas* (an *as* macro
45 pre-processor) documentation for further information.
49 | gcc / *as*: Prefix with '%'; for example `%eax`
50 | Intel: No extra punctuation; for example `eax`
54 | gcc / *as*: Prefix with '$'; for example `$4`
55 | Intel: No extra punctuation; for example `4`
59 | gcc / *as*: Prefix with '$'; for example `$loc`
60 | Intel: No extra punctuation; for example `loc`
64 | gcc / *as*: No extra punctuation; for example `loc`
65 | Intel: Square brackets; for example `[loc]`
69 | gcc / *as*: Parentheses; for example `(%eax)`
70 | Intel: Square brackets; for example `[eax]`
73 | *Hexadecimal numbers*
74 | gcc / *as*: Leading '0x' (C language syntax); for example `0xA0`
75 | Intel: Trailing 'h'; for example `A0h`
79 | gcc / *as*: Explicit in op code; for example `movw` to move a 16-bit word
80 | Intel: Implicit, deduced by assembler; for example `mov`
83 | *Instruction repetition*
84 | gcc / *as*: Split into two lines; for example
87 | Intel: Keep on one line; for example `rep stosl`
91 | gcc / *as*: Source first; for example `movw $4, %eax`
92 | Intel: Destination first; for example `mov eax, 4`
95 .. _A_Simple_Example_of_Inline_Assembler:
97 A Simple Example of Inline Assembler
98 ====================================
100 The following example will generate a single assembly language statement,
101 `nop`, which does nothing. Despite its lack of run-time effect,
102 the example will be useful in illustrating the basics of
103 the Inline Assembler facility.
107 with System.Machine_Code; use System.Machine_Code;
113 `Asm` is a procedure declared in package `System.Machine_Code`;
114 here it takes one parameter, a *template string* that must be a static
115 expression and that will form the generated instruction.
116 `Asm` may be regarded as a compile-time procedure that parses
117 the template string and additional parameters (none here),
118 from which it generates a sequence of assembly language instructions.
120 The examples in this chapter will illustrate several of the forms
121 for invoking `Asm`; a complete specification of the syntax
122 is found in the `Machine_Code_Insertions` section of the
123 :title:`GNAT Reference Manual`.
125 Under the standard GNAT conventions, the `Nothing` procedure
126 should be in a file named :file:`nothing.adb`.
127 You can build the executable in the usual way:
133 However, the interesting aspect of this example is not its run-time behavior
134 but rather the generated assembly code.
135 To see this output, invoke the compiler as follows:
139 $ gcc -c -S -fomit-frame-pointer -gnatp nothing.adb
141 where the options are:
144 compile only (no bind or link)
147 generate assembler listing
149 * :samp:`-fomit-frame-pointer`
150 do not set up separate stack frames
153 do not add runtime checks
155 This gives a human-readable assembler version of the code. The resulting
156 file will have the same name as the Ada source file, but with a `.s`
157 extension. In our example, the file :file:`nothing.s` has the following
177 The assembly code you included is clearly indicated by
178 the compiler, between the `#APP` and `#NO_APP`
179 delimiters. The character before the 'APP' and 'NOAPP'
180 can differ on different targets. For example, GNU/Linux uses '#APP' while
181 on NT you will see '/APP'.
183 If you make a mistake in your assembler code (such as using the
184 wrong size modifier, or using a wrong operand for the instruction) GNAT
185 will report this error in a temporary file, which will be deleted when
186 the compilation is finished. Generating an assembler file will help
187 in such cases, since you can assemble this file separately using the
188 *as* assembler that comes with gcc.
190 Assembling the file using the command
196 will give you error messages whose lines correspond to the assembler
197 input file, so you can easily find and correct any mistakes you made.
198 If there are no errors, *as* will generate an object file
202 .. _Output_Variables_in_Inline_Assembler:
204 Output Variables in Inline Assembler
205 ====================================
207 The examples in this section, showing how to access the processor flags,
208 illustrate how to specify the destination operands for assembly language
214 with Interfaces; use Interfaces;
215 with Ada.Text_IO; use Ada.Text_IO;
216 with System.Machine_Code; use System.Machine_Code;
217 procedure Get_Flags is
221 Asm ("pushfl" & LF & HT & -- push flags on stack
222 "popl %%eax" & LF & HT & -- load eax with flags
223 "movl %%eax, %0", -- store flags in variable
224 Outputs => Unsigned_32'Asm_Output ("=g", Flags));
225 Put_Line ("Flags register:" & Flags'Img);
228 In order to have a nicely aligned assembly listing, we have separated
229 multiple assembler statements in the Asm template string with linefeed
230 (ASCII.LF) and horizontal tab (ASCII.HT) characters.
231 The resulting section of the assembly output file is:
241 It would have been legal to write the Asm invocation as:
245 Asm ("pushfl popl %%eax movl %%eax, %0")
247 but in the generated assembler file, this would come out as:
252 pushfl popl %eax movl %eax, -40(%ebp)
255 which is not so convenient for the human reader.
258 at the end of each line to explain what the assembler instructions
259 actually do. This is a useful convention.
261 When writing Inline Assembler instructions, you need to precede each register
262 and variable name with a percent sign. Since the assembler already requires
263 a percent sign at the beginning of a register name, you need two consecutive
264 percent signs for such names in the Asm template string, thus `%%eax`.
265 In the generated assembly code, one of the percent signs will be stripped off.
267 Names such as `%0`, `%1`, `%2`, etc., denote input or output
268 variables: operands you later define using `Input` or `Output`
270 An output variable is illustrated in
271 the third statement in the Asm template string:
277 The intent is to store the contents of the eax register in a variable that can
278 be accessed in Ada. Simply writing `movl %%eax, Flags` would not
279 necessarily work, since the compiler might optimize by using a register
280 to hold Flags, and the expansion of the `movl` instruction would not be
281 aware of this optimization. The solution is not to store the result directly
282 but rather to advise the compiler to choose the correct operand form;
283 that is the purpose of the `%0` output variable.
285 Information about the output variable is supplied in the `Outputs`
290 Outputs => Unsigned_32'Asm_Output ("=g", Flags));
292 The output is defined by the `Asm_Output` attribute of the target type;
293 the general format is
297 Type'Asm_Output (constraint_string, variable_name)
299 The constraint string directs the compiler how
300 to store/access the associated variable. In the example
304 Unsigned_32'Asm_Output ("=m", Flags);
306 the `"m"` (memory) constraint tells the compiler that the variable
307 `Flags` should be stored in a memory variable, thus preventing
308 the optimizer from keeping it in a register. In contrast,
312 Unsigned_32'Asm_Output ("=r", Flags);
314 uses the `"r"` (register) constraint, telling the compiler to
315 store the variable in a register.
317 If the constraint is preceded by the equal character '=', it tells
318 the compiler that the variable will be used to store data into it.
320 In the `Get_Flags` example, we used the `"g"` (global) constraint,
321 allowing the optimizer to choose whatever it deems best.
323 There are a fairly large number of constraints, but the ones that are
324 most useful (for the Intel x86 processor) are the following:
326 ====== ==========================================
327 *=* output constraint
328 *g* global (i.e., can be stored anywhere)
337 *r* use one of eax, ebx, ecx or edx
338 *q* use one of eax, ebx, ecx, edx, esi or edi
339 ====== ==========================================
341 The full set of constraints is described in the gcc and *as*
342 documentation; note that it is possible to combine certain constraints
343 in one constraint string.
345 You specify the association of an output variable with an assembler operand
346 through the :samp:`%{n}` notation, where *n* is a non-negative
351 Asm ("pushfl" & LF & HT & -- push flags on stack
352 "popl %%eax" & LF & HT & -- load eax with flags
353 "movl %%eax, %0", -- store flags in variable
354 Outputs => Unsigned_32'Asm_Output ("=g", Flags));
357 `%0` will be replaced in the expanded code by the appropriate operand,
359 the compiler decided for the `Flags` variable.
361 In general, you may have any number of output variables:
363 * Count the operands starting at 0; thus `%0`, `%1`, etc.
365 * Specify the `Outputs` parameter as a parenthesized comma-separated list
366 of `Asm_Output` attributes
372 Asm ("movl %%eax, %0" & LF & HT &
373 "movl %%ebx, %1" & LF & HT &
375 Outputs => (Unsigned_32'Asm_Output ("=g", Var_A), -- %0 = Var_A
376 Unsigned_32'Asm_Output ("=g", Var_B), -- %1 = Var_B
377 Unsigned_32'Asm_Output ("=g", Var_C))); -- %2 = Var_C
379 where `Var_A`, `Var_B`, and `Var_C` are variables
382 As a variation on the `Get_Flags` example, we can use the constraints
383 string to direct the compiler to store the eax register into the `Flags`
384 variable, instead of including the store instruction explicitly in the
385 `Asm` template string:
389 with Interfaces; use Interfaces;
390 with Ada.Text_IO; use Ada.Text_IO;
391 with System.Machine_Code; use System.Machine_Code;
392 procedure Get_Flags_2 is
396 Asm ("pushfl" & LF & HT & -- push flags on stack
397 "popl %%eax", -- save flags in eax
398 Outputs => Unsigned_32'Asm_Output ("=a", Flags));
399 Put_Line ("Flags register:" & Flags'Img);
402 The `"a"` constraint tells the compiler that the `Flags`
403 variable will come from the eax register. Here is the resulting code:
413 The compiler generated the store of eax into Flags after
414 expanding the assembler code.
416 Actually, there was no need to pop the flags into the eax register;
417 more simply, we could just pop the flags directly into the program variable:
421 with Interfaces; use Interfaces;
422 with Ada.Text_IO; use Ada.Text_IO;
423 with System.Machine_Code; use System.Machine_Code;
424 procedure Get_Flags_3 is
428 Asm ("pushfl" & LF & HT & -- push flags on stack
429 "pop %0", -- save flags in Flags
430 Outputs => Unsigned_32'Asm_Output ("=g", Flags));
431 Put_Line ("Flags register:" & Flags'Img);
435 .. _Input_Variables_in_Inline_Assembler:
437 Input Variables in Inline Assembler
438 ===================================
440 The example in this section illustrates how to specify the source operands
441 for assembly language statements.
442 The program simply increments its input value by 1:
446 with Interfaces; use Interfaces;
447 with Ada.Text_IO; use Ada.Text_IO;
448 with System.Machine_Code; use System.Machine_Code;
449 procedure Increment is
451 function Incr (Value : Unsigned_32) return Unsigned_32 is
452 Result : Unsigned_32;
455 Outputs => Unsigned_32'Asm_Output ("=a", Result),
456 Inputs => Unsigned_32'Asm_Input ("a", Value));
464 Put_Line ("Value before is" & Value'Img);
465 Value := Incr (Value);
466 Put_Line ("Value after is" & Value'Img);
469 The `Outputs` parameter to `Asm` specifies
470 that the result will be in the eax register and that it is to be stored
471 in the `Result` variable.
473 The `Inputs` parameter looks much like the `Outputs` parameter,
474 but with an `Asm_Input` attribute.
475 The `"="` constraint, indicating an output value, is not present.
477 You can have multiple input variables, in the same way that you can have more
478 than one output variable.
480 The parameter count (%0, %1) etc, still starts at the first output statement,
481 and continues with the input statements.
483 Just as the `Outputs` parameter causes the register to be stored into the
484 target variable after execution of the assembler statements, so does the
485 `Inputs` parameter cause its variable to be loaded into the register
486 before execution of the assembler statements.
488 Thus the effect of the `Asm` invocation is:
490 * load the 32-bit value of `Value` into eax
491 * execute the `incl %eax` instruction
492 * store the contents of eax into the `Result` variable
494 The resulting assembler file (with *-O2* optimization) contains:
510 .. _Inlining_Inline_Assembler_Code:
512 Inlining Inline Assembler Code
513 ==============================
515 For a short subprogram such as the `Incr` function in the previous
516 section, the overhead of the call and return (creating / deleting the stack
517 frame) can be significant, compared to the amount of code in the subprogram
518 body. A solution is to apply Ada's `Inline` pragma to the subprogram,
519 which directs the compiler to expand invocations of the subprogram at the
520 point(s) of call, instead of setting up a stack frame for out-of-line calls.
521 Here is the resulting program:
525 with Interfaces; use Interfaces;
526 with Ada.Text_IO; use Ada.Text_IO;
527 with System.Machine_Code; use System.Machine_Code;
528 procedure Increment_2 is
530 function Incr (Value : Unsigned_32) return Unsigned_32 is
531 Result : Unsigned_32;
534 Outputs => Unsigned_32'Asm_Output ("=a", Result),
535 Inputs => Unsigned_32'Asm_Input ("a", Value));
538 pragma Inline (Increment);
544 Put_Line ("Value before is" & Value'Img);
545 Value := Increment (Value);
546 Put_Line ("Value after is" & Value'Img);
549 Compile the program with both optimization (*-O2*) and inlining
552 The `Incr` function is still compiled as usual, but at the
553 point in `Increment` where our function used to be called:
559 call _increment__incr.1
561 the code for the function body directly appears:
572 thus saving the overhead of stack frame setup and an out-of-line call.
575 .. _Other_`Asm`_Functionality:
577 Other `Asm` Functionality
578 =========================
580 This section describes two important parameters to the `Asm`
581 procedure: `Clobber`, which identifies register usage;
582 and `Volatile`, which inhibits unwanted optimizations.
584 .. _The_`Clobber`_Parameter:
586 The `Clobber` Parameter
587 -----------------------
589 One of the dangers of intermixing assembly language and a compiled language
590 such as Ada is that the compiler needs to be aware of which registers are
591 being used by the assembly code. In some cases, such as the earlier examples,
592 the constraint string is sufficient to indicate register usage (e.g.,
594 the eax register). But more generally, the compiler needs an explicit
595 identification of the registers that are used by the Inline Assembly
598 Using a register that the compiler doesn't know about
599 could be a side effect of an instruction (like `mull`
600 storing its result in both eax and edx).
601 It can also arise from explicit register usage in your
602 assembly code; for example:
606 Asm ("movl %0, %%ebx" & LF & HT &
608 Outputs => Unsigned_32'Asm_Output ("=g", Var_Out),
609 Inputs => Unsigned_32'Asm_Input ("g", Var_In));
611 where the compiler (since it does not analyze the `Asm` template string)
612 does not know you are using the ebx register.
614 In such cases you need to supply the `Clobber` parameter to `Asm`,
615 to identify the registers that will be used by your assembly code:
620 Asm ("movl %0, %%ebx" & LF & HT &
622 Outputs => Unsigned_32'Asm_Output ("=g", Var_Out),
623 Inputs => Unsigned_32'Asm_Input ("g", Var_In),
626 The Clobber parameter is a static string expression specifying the
627 register(s) you are using. Note that register names are *not* prefixed
628 by a percent sign. Also, if more than one register is used then their names
629 are separated by commas; e.g., `"eax, ebx"`
631 The `Clobber` parameter has several additional uses:
633 * Use 'register' name `cc` to indicate that flags might have changed
634 * Use 'register' name `memory` if you changed a memory location
637 .. _The_`Volatile`_Parameter:
639 The `Volatile` Parameter
640 ------------------------
642 .. index:: Volatile parameter
644 Compiler optimizations in the presence of Inline Assembler may sometimes have
645 unwanted effects. For example, when an `Asm` invocation with an input
646 variable is inside a loop, the compiler might move the loading of the input
647 variable outside the loop, regarding it as a one-time initialization.
649 If this effect is not desired, you can disable such optimizations by setting
650 the `Volatile` parameter to `True`; for example:
654 Asm ("movl %0, %%ebx" & LF & HT &
656 Outputs => Unsigned_32'Asm_Output ("=g", Var_Out),
657 Inputs => Unsigned_32'Asm_Input ("g", Var_In),
661 By default, `Volatile` is set to `False` unless there is no
664 Although setting `Volatile` to `True` prevents unwanted
665 optimizations, it will also disable other optimizations that might be
666 important for efficiency. In general, you should set `Volatile`
667 to `True` only if the compiler's optimizations have created