banner



How To Display The Contents Of A Register In Assembly In Gcc

  • Download source files - ane.86 KB

Sample Image - edujini_inline_asm.jpg

Introduction

First of all, what does term "inline" hateful?

Generally the inline term is used to instruct the compiler to insert the code of a part into the code of its caller at the point where the actual phone call is fabricated. Such functions are chosen "inline functions". The benefit of inlining is that it reduces part-telephone call overhead.

Now, it's easier to judge well-nigh inline assembly. It is just a set of assembly instructions written as inline functions. Inline assembly is used for speed, and you ought to believe me that it is frequently used in arrangement programming.

We can mix the assembly statements within C/C++ programs using keyword asm. Inline assembly is important because of its power to operate and brand its output visible on C/C++ variables.

GCC Inline Assembly Syntax

Assembly linguistic communication appears in ii flavors: Intel Style & AT&T fashion. GNU C compiler i.e. GCC uses AT&T syntax and this is what we would utilize. Let us look at some of the major differences of this fashion equally confronting the Intel Style.

If you are wondering how you can utilise GCC on Windows, yous tin only download Cygwin from world wide web.cygwin.com.

  1. Register Naming: Register names are prefixed with %, so that registers are %eax, %cl etc, instead of just eax, cl.
  2. Ordering of operands: Unlike Intel convention (commencement operand is destination), the gild of operands is source(s) get-go, and destination last. For case, Intel syntax "mov eax, edx" will look like "mov %edx, %eax" in AT&T assembly.
  3. Operand Size: In AT&T syntax, the size of memory operands is adamant from the final character of the op-lawmaking name. The suffix is b for (8-flake) byte, w for (sixteen-bit) give-and-take, and l for (32-scrap) long. For example, the correct syntax for the above instruction would have been "movl %edx, %eax".
  4. Firsthand Operand: Immediate operands are marked with a $ prefix, as in "addl $5, %eax", which means add immediate long value five to register %eax).
  5. Memory Operands: Missing operand prefix indicates it is a memory-address; hence "movl $bar, %ebx" puts the address of variable bar into annals %ebx, merely "movl bar, %ebx" puts the contents of variable bar into register %ebx.
  6. Indexing: Indexing or indirection is done by enclosing the index annals or indirection memory cell address in parentheses. For example, "movl 8(%ebp), %eax" (moves the contents at offset 8 from the cell pointed to by %ebp into register %eax).

For all our lawmaking, nosotros would exist working on Intel x86 processors. This information is necessary since all instructions may or may not work with other processors.

Bones Inline Lawmaking

We tin use either of the following formats for bones inline assembly.

asm("          assembly code");

or

          __asm__ ("          assembly lawmaking")

Example:

asm("          movl %ebx, %eax");           __asm__("          movb %ch, (%ebx)")

Just in case we have more than than one assembly teaching, utilise semicolon at the stop of each instruction.

Please refer to the example below (bachelor in basic_arithmetic.c in downloads).

          #include                      <            stdio.h            >                    int          primary() {               __asm__ (          "          movl $10, %eax;"          "          movl $20, %ebx;"          "          addl %ebx, %eax;"          )           __asm__ (          "          movl $10, %eax;"          "          movl $20, %ebx;"          "          subl %ebx, %eax;"          )           __asm__ (          "          movl $10, %eax;"          "          movl $xx, %ebx;"          "          imull %ebx, %eax;"          )      return          0           }

Compile it using "-thousand" pick of GNU C compiler "gcc" to go along debugging information with the executable and and so using GNU Debugger "gdb" to audit the contents of CPU registers.

Extended Assembly

In extended associates, nosotros can also specify the operands. It allows u.s.a. to specify the input registers, output registers and a list of clobbered registers.

asm (          "          associates lawmaking"          : output operands                              : input operands                               : list of clobbered registers       );

If at that place are no output operands but in that location are input operands, we must place two sequent colons surrounding the place where the output operands would go.

Information technology is non mandatory to specify the list of clobbered registers to use, we tin leave that to GCC and GCC's optimization scheme do the needful.

Case (ane)

asm ("          movl %%eax, %0;"          :          "          =r"          ( val ));

In this example, the variable "val" is kept in a register, the value in annals eax is copied onto that register, and the value of "val" is updated into the retentiveness from this annals.

When the "r" constraint is specified, gcc may proceed the variable in any of the available General Purpose Registers. We can also specify the register names direct by using specific register constraints.

The register constraints are equally follows :

+---+--------------------+ | r |    Register(s)     | +---+--------------------+ | a |   %eax, %ax, %al   | | b |   %ebx, %bx, %bl   | | c |   %ecx, %cx, %cl   | | d |   %edx, %dx, %dl   | | Southward |   %esi, %si        | | D |   %edi, %di        | +---+--------------------+

Example (2)

          int          no =          100, val ;     asm ("          movl %ane, %%ebx;"          "          movl %%ebx, %0;"          :          "          =r"          ( val )                  :          "          r"          ( no )                   :          "          %ebx"                );        

In the above example, "val" is the output operand, referred to by %0 and "no" is the input operand, referred to by %1. "r" is a constraint on the operands, which says to GCC to use any annals for storing the operands.

Output operand constraint should accept a constraint modifier "=" to specify the output operand in write-only manner. There are two %'s prefixed to the register name, which helps GCC to distinguish between the operands and registers. operands accept a unmarried % as prefix.

The clobbered annals %ebx afterwards the third colon informs the GCC that the value of %ebx is to be modified within "asm", and so GCC won't utilize this register to shop whatever other value.

Case (3)

          int          arg1, arg2, add ;          __asm__ (          "          addl %%ebx, %%eax;"          :          "          =a"          (add)         :          "          a"          (arg1),          "          b"          (arg2) )

Here "add" is the output operand referred to by register eax. And arg1 and arg2 are input operands referred to by registers eax and ebx respectively.

Let united states of america see a complete example using extended inline assembly statements. It performs uncomplicated arithmetics operations on integer operands and displays the result (bachelor as arithmetic.c in downloads).

          #include                      <            stdio.h            >                    int          master() {          int          arg1, arg2, add together, sub, mul, quo, rem ;      printf(          "          Enter two integer numbers : "          );     scanf(          "          %d%d", &arg1, &arg2 );                __asm__ (          "          addl %%ebx, %%eax;"          :          "          =a"          (add) :          "          a"          (arg1) ,          "          b"          (arg2) )     __asm__ (          "          subl %%ebx, %%eax;"          :          "          =a"          (sub) :          "          a"          (arg1) ,          "          b"          (arg2) )     __asm__ (          "          imull %%ebx, %%eax;"          :          "          =a"          (mul) :          "          a"          (arg1) ,          "          b"          (arg2) )      __asm__ (          "          movl $0x0, %%edx;"          "          movl %2, %%eax;"          "          movl %3, %%ebx;"          "          idivl %%ebx;"          :          "          =a"          (quo),          "          =d"          (rem) :          "          g"          (arg1),          "          thou"          (arg2) )      printf(          "          %d + %d = %d\n", arg1, arg2,          add          )     printf(          "          %d - %d = %d\n", arg1, arg2,          sub          )     printf(          "          %d * %d = %d\north", arg1, arg2,          mul          )     printf(          "          %d / %d = %d\n", arg1, arg2, quo )     printf(          "          %d %% %d = %d\n", arg1, arg2, rem )      return          0           }

Volatile

If our associates statement must execute where we put it, (i.e. must not exist moved out of a loop every bit an optimization), put the keyword "volatile" or "__volatile__" afterward "asm" or "__asm__" and earlier the ()s.

asm          volatile          (          "          ...;"          "          ...;"          : ... );

or

          __asm__ __volatile__ (          "          ...;"          "          ...;"          : ... )

Refer to the following instance, which computes the Greatest Common Divisor using well known Euclid'due south Algorithm ( honoured as first algorithm).

          #include                      <            stdio.h            >                    int          gcd(          int          a,          int          b ) {          int          event ;               __asm__ __volatile__ (          "          movl %1, %%eax;"          "          movl %2, %%ebx;"          "          CONTD: cmpl $0, %%ebx;"          "          je DONE;"          "          xorl %%edx, %%edx;"          "          idivl %%ebx;"          "          movl %%ebx, %%eax;"          "          movl %%edx, %%ebx;"          "          jmp CONTD;"          "          Washed: movl %%eax, %0;"          :          "          =g"          (result) :          "          one thousand"          (a),          "          yard"          (b)     )      return upshot  }          int          main() {          int          first, 2d ;     printf(          "          Enter two integers : "          ) ;     scanf(          "          %d%d", &first, &second );      printf(          "          GCD of %d & %d is %d\due north", outset, second, gcd(first, 2nd) ) ;          render          0          ; }

Hither are some more examples which use FPU (Floating Betoken Unit) Instruction Ready.

An example program to perform simple floating point arithmetic:

          #include                      <            stdio.h            >                    int          main() {          float          arg1, arg2, add, sub, mul, div ;      printf(          "          Enter two numbers : "          );     scanf(          "          %f%f", &arg1, &arg2 );                __asm__ (          "          fld %i;"          "          fld %ii;"          "          fadd;"          "          fstp %0;"          :          "          =one thousand"          (add) :          "          g"          (arg1),          "          g"          (arg2) )       __asm__ (          "          fld %ii;"          "          fld %1;"          "          fsub;"          "          fstp %0;"          :          "          =grand"          (sub) :          "          g"          (arg1),          "          g"          (arg2) )       __asm__ (          "          fld %1;"          "          fld %2;"          "          fmul;"          "          fstp %0;"          :          "          =one thousand"          (mul) :          "          g"          (arg1),          "          g"          (arg2) )       __asm__ (          "          fld %2;"          "          fld %1;"          "          fdiv;"          "          fstp %0;"          :          "          =g"          (div) :          "          g"          (arg1),          "          g"          (arg2) )       printf(          "          %f + %f = %f\n", arg1, arg2,          add          )     printf(          "          %f - %f = %f\due north", arg1, arg2,          sub          )     printf(          "          %f * %f = %f\north", arg1, arg2,          mul          )     printf(          "          %f / %f = %f\due north", arg1, arg2,          div          )      render          0           }

Example program to compute trigonometrical functions like sin and cos:

          #include                      <            stdio.h            >                    float          sinx(          float          degree ) {          float          result, two_right_angles =          180.0f          ;               __asm__ __volatile__ (          "          fld %1;"          "          fld %2;"          "          fldpi;"          "          fmul;"          "          fdiv;"          "          fsin;"          "          fstp %0;"          :          "          =g"          (consequence) :          "          g"(two_right_angles),          "          chiliad"          (degree)     )      return result  }          bladder          cosx(          float          caste ) {          float          event, two_right_angles =          180.0f, radians ;               __asm__ __volatile__ (          "          fld %1;"          "          fld %2;"          "          fldpi;"          "          fmul;"          "          fdiv;"          "          fstp %0;"          :          "          =g"          (radians) :          "          g"(two_right_angles),          "          g"          (caste)     )      __asm__ __volatile__ (          "          fld %ane;"          "          fcos;"          "          fstp %0;"          :          "          =yard"          (outcome) :          "          m"          (radians)     )      render consequence  }          bladder          square_root(          float          val ) {          float          upshot ;          __asm__ __volatile__ (          "          fld %1;"          "          fsqrt;"          "          fstp %0;"          :          "          =m"          (result) :          "          g"          (val)     )      return result  }          int          main() {          bladder          theta ;     printf(          "          Enter theta in degrees : "          ) ;     scanf(          "          %f", &theta ) ;      printf(          "          sinx(%f) = %f\n", theta, sinx( theta ) );     printf(          "          cosx(%f) = %f\n", theta, cosx( theta ) );     printf(          "          square_root(%f) = %f\n", theta, square_root( theta ) ) ;          return          0          ; }

Summary

GCC uses AT&T style assembly statements and we can use asm keyword to specify bones besides as extended associates instructions. Using inline associates tin reduce the number of instructions required to be executed by the processor. In our example of GCD, if we implement using inline assembly, the number of instructions required for adding would be much less as compared to normal C code using Euclid'southward Algorithm.

You lot tin also visit Eduzine© - electronic technology magazine of EduJini, the company that I work with.

History

  • 15th October, 2006: Initial mail

Source: https://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C

Posted by: contrerasknitted.blogspot.com

0 Response to "How To Display The Contents Of A Register In Assembly In Gcc"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel