In-line Assembler in C

In-line assembler in C, as in Pascal, uses the asm keyword, but the syntax is more difficult. We show first the default syntax, AT&T, for Intel-type processors and then some ARM in-line assembler for the Raspberry Pi. The assembler code is within brackets and the instructions, separated by a semicolon or \n (for a new line), are within double quotes. You can access variables (declared as usual in C outside of the asm block) by denoting them as for output e.g. "=r" (my_output1) or for input e.g. : "r" (my_input1). In an assembler statement you refer to the first variable following a colon as %0, to the second as %1 etc. The use of the % symbol for variables has the consequence that you must prefix a register (such as EAX) with a second %.

As usual, experimenting with little working examples is helpful. See this page for more complicated possibilities.

Demonstration of variables for input to and output from the asm block:

#include <stdio.h>

int main()
{
  int input = 10;
  int output1, output2;
  asm (
        "mov %2, %0;"
        "mov %2, %1;"
        :"=r"(output1), "=r" (output2) //%0 and %1
        :"r"(input) //%2
      );
  printf("output1: %d\noutput2: %d", output1, output2);
  return 0;
}    

Output to console:

output1: 10
output2: 10

The code of the second example is based on our Pascal program ASM_AddSubA.

#include <stdio.h>

int main()
{
  int int1 = 10, int2 = 50;
  asm (
        "ADD $5, %0;"
        "SUB $30, %1;"
        : "+r" (int1), "+r" (int2) // %0 and %1
      );
  printf("10 + 5 = %d\n50 - 30 = %d", int1, int2);
  return 0;
}     

This is neater than supplying separate variables for input and output:

#include <stdio.h>

int main()
{
  int int1 = 10, output_add, int2 = 50, output_sub;
  asm (
        "ADD $5, %2;"
        "MOV %2, %0;"
        "SUB $30, %3;"
        "MOV %3, %1;"
        : "=r" (output_add), "=r" (output_sub)  //%0 and %1
        : "r" (int1), "r" (int2) // %2 and %3
      );
  printf("10 + 5 = %d\n50 - 30 = %d", output_add, output_sub);
  return 0;
}
    

Output:

10 + 5 = 15
50 - 30 = 20

The final example is based on the Pascal program ASMLoop1A. We changed the label from .LStart (which gave an error message) to loop_start.

#include <stdio.h>

int main()
{
  int total;
  asm(
       "MOV $0xA, %%ECX;" // Sets count to 10
       "MOV $0x0, %%EAX;" // Initialises accumulator to 0
       "loop_start:;"
       "ADD %%ECX, %%EAX;"  // Adds count to accumulator
       // Decrement ECX and go back to loop_start if ECX does not hold 0
       "Loop loop_start;"
       // Give variable total its final value from the accumulator
       "MOV %%EAX, %0;"
       : "=r" (total)
     );
  printf("total: %d\n", total);
  return 0;
}    

Output:

total: 55

 

ARM in-line assembler for the Raspberry Pi

These are equivalent programs of the above for the Raspberry Pi. See the ARM GCC Inline Assembler Cookbook for guidance if you want to try to do something useful with ARM on-line assembler.

#include <stdio.h>

int main()
{
  int input = 10;
  int output1, output2;
  asm(
       "mov %[out1], %[inp];"
       "mov %[out2], %[inp];"
       : [out1] "=r" (output1), [out2] "=r" (output2)
       : [inp] "r" (input)
     );

  printf("output1: %d\noutput2: %d", output1, output2);
  return 0;
}    

Output to console:

output1: 10
output2: 10

#include <stdio.h>

int main()
{
  int int1 = 10, int2 = 50;
  asm(
       "add %[i1], #5;"
       "sub %[i2], #20;"
       : [i1] "+r" (int1), [i2] "+r" (int2)
     );

  printf("int1: %d\nint2: %d", int1, int2);
  return 0;
}    

Output to console:

int1: 15
int2: 30

#include <stdio.h>

int main()
{
  int total = 0;
  asm(
       "mov %%r0, #0;" 
       "mov %%r1, #10;" // loop control
       "loop_start:;"
       "add %%r0, %%r1;"
       "subs %%r1, #1;"
       "bne loop_start;"
       "MOV %[tot], %%r0;"
       : [tot] "=r" (total)
     );

  printf("total: %d", total);
  return 0;
}    

Output to console:

total: 55
Programming - a skill for life!

How to apply your knowledge of Pascal when learning C/C++