1 / 19

* See see http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C- C

Machine-Level Programming VIII: inline Assembly Comp 21000: Introduction to Computer Systems & Assembly Lang On-Line resources*. * See see http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C- C. Today. Inline assembly Example. Why use assembly?. To access hardware directly

borna
Télécharger la présentation

* See see http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C- C

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Machine-Level Programming VIII:inline Assembly Comp 21000: Introduction to Computer Systems & Assembly LangOn-Line resources* * See see http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C

  2. Today • Inline assembly • Example

  3. Why use assembly? • To access hardware directly • linux OS code sometimes does this • See usr/include/asm/io.h • contains assembly to directly access i/o ports. • See usr/src/linux/arch/i386/kernel/process.s • uses hlt instruction in idle loop code. • Many examples in usr/src/linux/arch • Many examples in usr/src/linux/drivers • often in drivers need to specify how to access registers in the driver.

  4. Why use assembly? • Speed • Be careful! Optimizing compilers are almost always better! • useful when you know an assembly language instruction that can replace a library call • Example: transcendental function computation • See /usr/include/bits/mathinline.h • has macros for some inline assembly squences • Example: if spend most of the time in a loop computing the sine and cosine of the same angles, could use the fsincos assembly function • We’ll see an example later

  5. inline assembly code* • Example: • mov instruction /* put this line in your C program*/asm("assemblycode"); /* alternative syntax */__asm__ ("assemblycode"); asm("movl %ebx, %eax"); /* moves the contents of ebx register to eax */ __asm__("movb %ch, (%ebx)"); /* moves the byte from ch to the memory pointed by ebx */ * see http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C

  6. inline assembly • More sophisticated assembly • For more than one assembly instruction, use semicolon at the end of each instruction of inserted code • see example on next slide

  7. Example #include <stdio.h> int main() { /* Add 10 and 20 and store result into register %eax */ __asm__ ( "movl $10, %eax;" "movl $20, %ebx;" "addl %ebx, %eax;" ); /* Subtract 20 from 10 and storeresultintoregister %eax */ __asm__ ( "movl $10, %eax;" "movl $20, %ebx;" "subl %ebx, %eax;" ); /* Multiply 10 and 20 and store result into register %eax */ __asm__ ( "movl $10, %eax;" "movl $20, %ebx;" "imull %ebx, %eax;" ); return 0 ; } compile with –m32 –O1 flags trace in gdb to see registers change.

  8. Extended inline assembly • Idea • In extended assembly, we can also specify the operands • can specify the input registers, output registers and a list of clobbered registers. • If there are no output operands but there are input operands, we must place two consecutive colons surrounding the place where the output operands would go. • Can omit list of clobbered registers to use, • GCC and GCC’s optimization scheme will take care of the reg. asm ( "assemblycode" : output operands /* optional */ : input operands /* optional */ : list of clobbered registers /* optional */ );

  9. Example 1 • The variable "val" is kept in a register • val is a C variable that must be declared earlier in the C program • the value in register %eaxis copied onto that register, • and the value of "val" is updated into the memory from that register. • note that eax is preceded by 2 percent signs • differentiate from a asm parameter (like printf) asm ("movl %%eax, %0;" : "=r" ( val ));

  10. Example 1 • the %0 indicates the first operand of asm, it is associated with the first parameter, i.e., val • “=r” indicates a register constraint • see chart on next page for all possible register specifications • “r” indicates that gccmay keep the variable in any available General Purpose Registers • the “=“ indicates write only mode. asm ("movl %%eax, %0;" : "=r" ( val )); see ~barr/Student/Comp210/inline directory for all examples

  11. register specifiers

  12. Example 2 int no = 100, val ; asm("movl %1, %%ebx;" "movl %%ebx, %0;" : "=r" ( val ) /* output */ : "r" ( no ) /* input */ : "%ebx" /* clobbered register */ ); • Two variables are declared in the C code, no and val • %0 is the first operand to asm and thus refers to the C variable val(the output variable) • %1 is the second operand and thus refers to the C variable no (the input variable) • “=r” and “r” say that gcc can use any registers to store the corresponding variable (either valor no ) • the clobbered variable is %ebx so gcc should not use that variable anywhere else.

  13. Example 3 int arg1, arg2, add ; arg1 = 10; arg2 = 25; __asm__ ( "addl %%ebx, %%eax;" : "=a" (add) : "a" (arg1), "b" (arg2) ); • The C code declares three variables: arg1, arg2, add • The input variables will use %eax (for arg1) and %ebx (for arg2) • the output variable is add and will use register %eax • no clobber register is set; gcc can determine

  14. #include <stdio.h> int main() { int arg1, arg2, add, sub, mul, quo, rem ; printf( "Enter two integer numbers : " ); scanf( "%d%d", &arg1, &arg2 ); /* PerformAddition, Subtraction, Multiplication & Division */ __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), "g" (arg2) ); printf( "%d + %d = %d\n", arg1, arg2, add ); printf( "%d - %d = %d\n", arg1, arg2, sub ); printf( "%d * %d = %d\n", arg1, arg2, mul ); printf( "%d / %d = %d\n", arg1, arg2, quo ); printf( "%d %% %d = %d\n", arg1, arg2, rem ); return 0 ; } Example 4 Example 4 idivlS # Signed divide R[%edx] R[%edx]:R[%eax] mod S; R[%eax] R[%edx]:R[%eax] / S

  15. #include <stdio.h> #include <stdlib.h> int main (intargc, char* argv[]) { long max = atoi (argv[1]); long number; long i; unsigned position; volatile unsigned result; /* Repeat the operation for a large number of values. */ for (number = 1; number <= max; ++number) { /* Repeatedly shift the number to the right, until the result is zero. Keep count of the number of shifts this requires. */ for (i = (number >> 1), position = 0; i != 0; ++position) i>>= 1; /* The position of the most significant set bit is the number of shifts we needed after the first one. */ result = position; } // end outer for loop return 0; } // end main Example 4 Example 5 why use inline assembly? no assembly in this code % gcc-O2 -o bit-pos-loop bit-pos-loop.c % time ./bit-pos-loop 250000000 19.51user 0.00 system 0:20.40 elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k0inputs+0outputs (73major+11minor)pagefaults 0swaps

  16. #include <stdio.h> #include <stdlib.h> int main (intargc, char* argv[]) { long max = atoi (argv[1]); long number; unsigned position; volatile unsigned result; /* Repeat the operation for a large number of values. */ for (number = 1; number <= max; ++number) { /* Compute the position of the most significant set bit using the bsrl assembly instruction. */ asm(“bsrl %1, %0” : “=r” (position) : “r” (number)); result = position; } // end for loop return 0; } Example 4 Example 5 why use inline assembly? assembly used for inner loop %gcc-O2 -o bit-pos-asm bit-pos-asm.c % time ./bit-pos-asm250000000 3.19user 0.00system 0:03.32elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k0inputs+0outputs (73major+11minor)pagefaults 0swaps Compare to the 19.51user of the previous C only example!

  17. Volitile • If our assembly statement must execute where we put it, (i.e. must not be moved out of a loop as an optimization), put the keyword "volatile" or "__volatile__" after "asm" or "__asm__" and before the ()s. asm volatile ( "...;” "...;" : ... ); __asm__ __volatile__ ( "...;" "...;" : ... );

  18. #include <stdio.h> intgcd( int a, int b ) { int result ; /* Compute Greatest Common Divisor using Euclid's Algorithm */ __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;" "DONE: movl %%eax, %0;" : "=g" (result) : "g" (a), "g" (b) ); return result; } intmain() { intfirst, second ; printf( "Enter twointegers : " ) ; scanf( "%d%d", &first, &second ); printf( "GCD of %d & %d is %d\n", first, second, gcd(first, second) ) ; return 0 ; } Example 4 Example 6 Compute GCD with Euclid’s Algm Note that we can put labels and jump to them! Note that we can put several asm instructions in one __asm__ function call

  19. #include <stdio.h> int main() { int x, y, rslt, rtnval; inti; printf("Enter two integers\n"); rslt = scanf("%d%d", &x, &y); /* change into assembly code */ rtnval = 0; for(i = 0; i < y; i++) { rtnval += x; } /* end change */ printf("%d * %d = %d\n", x, y, rtnval); return 0; } Example 6 convert the for loop to assembly code (should be no more than 11 lines of assembly code)

More Related