1. Implementation goals
Use assembler to call the C-database function, that is, the function can be called when the function name and parameter are given.
II. Problem description
when implementing the C interpreter, parse the function call statement, for example, strlen ("linxr"); then, how do I call the strlen function?
first, obtain the parameter list arg_listk, and then call the stlen function using the Code in the following format:
If (strcmp (token, "strlen") = 0) {
strlen (arg_list [0]);
}< br> else if (...) {
}< br>...
[problem] in this way, there are hundreds of library functions in C, so this code will become endless.
3. Solve the problem
based on the above problem. I came up with a way to call the C-library function with a unified entry. The function prototype is tentatively set to
int cCall (void * Fapp, var_t * arg_list);
Fapp: function address
arg_list: parameter list, var_t is the variable type I have defined, which is not described here.
to call the cCall function, you must first do two things:
1. You must obtain the corresponding function pointer Based on the function name.
now I am using a list to maintain the pointer of all c-database functions, which can be defined as follows:
struct cpp_t {
char * fname;
char * Fapp;
} cpp_table [100] ={< br> "strlen", (char *) strlen,
"strcpy ", (char *) strcpy,
....
}< br> the function pointer can be searched by function name to traverse the table, but the efficiency is relatively low. I have implemented all hash tables, which are not detailed here.
2. You must obtain a list of parameters based on the function call statement. How to implement it is about Syntax Parsing. :)
IV. Implementation of the cCall Function
If you understand the function calling rules of C, this problem will be quite simple. Here is a brief description:
For example, call printf ("% d", 1, 2 );
The C language calling rules (I .e. _ cdecl) are as follows:
Push 2
Push 1
Push 0x123456; Set 0x123456 to the address of the string "% d"
Call 0xa0b1c2; Set 0xa0b1c2 to the address of printf
Add ESP, 12; balance the stack here
So it's easy. We only need to let C call Assembly to implement this cCall function.
The following assembly is compiled using MASM. Compile command:ML/C/COFF/Zi/FL cCall. ASM
[CCall. ASM Code]
Title cCall
. 386
. Model flat, c
. Data?
Arg_num DWORD 0
Arg_tab DWORD 100 DUP ( 0 )
Arg_tye DWORD 100 DUP ( 0 )
Fun_ptr DWORD 0
. Code
Push_arg_ini proc
MoV Arg_num, 0
RET
Push_arg_ini endp
Push_arg proc, Arg: sdword, Tye: sdword
MoV Eax, arg_num
MoV EBX, offset arg_tab
MoV ECX, ARG
MoV [EBX + eax * 4 ], ECx
MoV EBX, offset arg_tye
MoV ECX, Tye
MoV [EBX + eax * 4 ], ECx
Add Eax, 1
MoV Arg_num, eax
RET
Push_arg endp
Push_fun proc, fun: sdword
MoV Eax, fun
MoV Fun_ptr, eax
RET
Push_fun endp
I _fun_call proc
Local count: DWORD
XOR Eax, eax
MoV EBX, offset arg_tab
MoV ECX, offset arg_tye
MoV Count, 0
. While eax <arg_num
MoV EdX, [ECx + eax * 4 ]
; Floating point type inbound stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;
. If edX
Bytes Dword ptr [EBX + eax * 4 ]
Sub ESP, 8
Fstp Qword PTR [esp]
. Elseif
Push [EBX + eax * 4 ]
. Endif
Add Eax, 1
Add Count, 4
. Endw
MoV Eax, fun_ptr
Call Eax
Add ESP, count
RET
I _fun_call endp
F_fun_call proc
Local count: DWORD
XOR Eax, eax
MoV EBX, offset arg_tab
MoV ECX, offset arg_tye
MoV Count, 0
. While eax <arg_num
MoV EdX, [ECx + eax * 4 ]
; Floating point type inbound stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;
. If edX
Bytes Dword ptr [EBX + eax * 4 ]
Sub ESP, 8
Fstp Qword PTR [esp]
. Elseif
Push [EBX + eax * 4 ]
. Endif
Add Eax, 1
Add Count, 4
. Endw
MoV Eax, fun_ptr
Call Eax
Add ESP, count
RET
f_fun_call endp
end
declare these functions in C:
int _ cdecl push_arg_ini ();
int _ cdecl push_arg (INT Arg, int Tye );
int _ cdecl push_fun (INT fun);
int _ cdecl I _fun_call ();
double _ cdecl f_fun_call ();
in this way, if you want to call the strlen function in C, you can call the function as follows:
push_arg_ini ();
push_arg (INT) "linxr", 0); // The second parameter here is the parameter type, because the floating point type's inbound stack mode is different from the integer type
push_fun (INT) strlen );
I _fun_call (); // f_fun_call is used to return the double type.
In fact, calling any c-database function can be implemented in this way, so we can easily define and implement the above cCall function.
int cCall (void * Fapp, var_t * arg_list)
{< br> int I;
push_arg_ini ();
for (I = 0; I push_arg (arg_list [I]. value, arg_list [I]. type);
}< br> push_fun (INT) Fapp);
return I _fun_call ();
}< br> return the double type cCall...