[ Pobierz całość w formacie PDF ]
4.7.7 Examples
Next is an example that shows how an assembly routine can be interfaced
to a C program. (Note that this program does not use the assembly skeleton
program (Figure 1.7) or the driver.c module.)
main5.c
1 #include
2 /" prototype for assembly routine "/
3 void calc sum( int , int " ) attribute ((cdecl));
4
5 int main( void )
6 {
7 int n, sum;
8
9 printf ( Sum integers up to : );
10 scanf( %d , &n);
11 calc sum(n, &sum);
12 printf ( Sum is %d\n , sum);
13 return 0;
14 }
main5.c
sub5.asm
1 ; subroutine _calc_sum
2 ; finds the sum of the integers 1 through n
3 ; Parameters:
4 ; n - what to sum up to (at [ebp + 8])
5 ; sump - pointer to int to store sum into (at [ebp + 12])
6 ; pseudo C code:
7 ; void calc_sum( int n, int * sump )
8 ; {
9 ; int i, sum = 0;
10 ; for( i=1; i
11 ; sum += i;
12 ; *sump = sum;
13 ; }
14
15 segment .text
16 global _calc_sum
17 ;
86 CHAPTER 4. SUBPROGRAMS
Sum integers up to: 10
Stack Dump # 1
EBP = BFFFFB70 ESP = BFFFFB68
+16 BFFFFB80 080499EC
+12 BFFFFB7C BFFFFB80
+8 BFFFFB78 0000000A
+4 BFFFFB74 08048501
+0 BFFFFB70 BFFFFB88
-4 BFFFFB6C 00000000
-8 BFFFFB68 4010648C
Sum is 55
Figure 4.13: Sample run of sub5 program
18 ; local variable:
19 ; sum at [ebp-4]
20 _calc_sum:
21 enter 4,0 ; make room for sum on stack
22 push ebx ; IMPORTANT!
23
24 mov dword [ebp-4],0 ; sum = 0
25 dump_stack 1, 2, 4 ; print out stack from ebp-8 to ebp+16
26 mov ecx, 1 ; ecx is i in pseudocode
27 for_loop:
28 cmp ecx, [ebp+8] ; cmp i and n
29 jnle end_for ; if not i
30
31 add [ebp-4], ecx ; sum += i
32 inc ecx
33 jmp short for_loop
34
35 end_for:
36 mov ebx, [ebp+12] ; ebx = sump
37 mov eax, [ebp-4] ; eax = sum
38 mov [ebx], eax
39
40 pop ebx ; restore ebx
41 leave
42 ret
sub5.asm
4.7. INTERFACING ASSEMBLY WITH C 87
Why is line 22 ofsub5.asmso important? Because the C calling con-
vention requires the value of EBX to be unmodified by the function call. If
this is not done, it is very likely that the program will not work correctly.
Line 25 demonstrates how thedumpstackmacro works. Recall that the
first parameter is just a numeric label, and the second and third parameters
determine how many double words to display below and above EBP respec-
tively. Figure 4.13 shows an example run of the program. For this dump,
one can see that the address of the dword to store the sum is BFFFFB80 (at
EBP + 12); the number to sum up to is 0000000A (at EBP + 8); the return
address for the routine is 08048501 (at EBP + 4); the saved EBP value is
BFFFFB88 (at EBP); the value of the local variable is 0 at (EBP - 4); and
finally the saved EBX value is 4010648C (at EBP - 8).
Thecalcsumfunction could be rewritten to return the sum as its return
value instead of using a pointer parameter. Since the sum is an integral
value, the sum should be left in the EAX register. Line 11 of themain5.c
file would be changed to:
sum = calc sum(n);
Also, the prototype ofcalcsumwould need be altered. Below is the modi-
fied assembly code:
sub6.asm
1 ; subroutine _calc_sum
2 ; finds the sum of the integers 1 through n
3 ; Parameters:
4 ; n - what to sum up to (at [ebp + 8])
5 ; Return value:
6 ; value of sum
7 ; pseudo C code:
8 ; int calc_sum( int n )
9 ; {
10 ; int i, sum = 0;
11 ; for( i=1; i
12 ; sum += i;
13 ; return sum;
14 ; }
15 segment .text
16 global _calc_sum
17 ;
18 ; local variable:
19 ; sum at [ebp-4]
20 _calc_sum:
21 enter 4,0 ; make room for sum on stack
88 CHAPTER 4. SUBPROGRAMS
1 segment .data
2 format db "%d", 0
3
4 segment .text
5 ...
6 lea eax, [ebp-16]
7 push eax
8 push dword format
9 call _scanf
10 add esp, 8
11 ...
Figure 4.14: Callingscanffrom assembly
22
23 mov dword [ebp-4],0 ; sum = 0
24 mov ecx, 1 ; ecx is i in pseudocode
25 for_loop:
26 cmp ecx, [ebp+8] ; cmp i and n
27 jnle end_for ; if not i
28
29 add [ebp-4], ecx ; sum += i
30 inc ecx
31 jmp short for_loop
32
33 end_for:
34 mov eax, [ebp-4] ; eax = sum
35
36 leave
37 ret
sub6.asm
4.7.8 Calling C functions from assembly
One great advantage of interfacing C and assembly is that allows as-
sembly code to access the large C library and user-written functions. For
example, what if one wanted to call thescanffunction to read in an integer
from the keyboard? Figure 4.14 shows code to do this. One very important
point to remember is thatscanffollows the C calling standard to the letter.
This means that it preserves the values of the EBX, ESI and EDI registers;
however, the EAX, ECX and EDX registers may be modified! In fact, EAX
will definitely be changed, as it will contain the return value of thescanf
[ Pobierz całość w formacie PDF ]