📄 ccall.gml
字号:
.note
All used 80x86 registers except registers EAX, ECX and EDX must be saved on
entry and restored on exit.
Segment registers DS and ES must also be saved on entry and restored on
exit.
Segment register ES does not have to be saved and restored when using a
memory model that is not a small data model.
.ix 'options' 'r'
Note that segment registers only have to be saved and restored if you are
compiling your application with the "r" option.
.note
The direction flag must be clear before returning to the caller.
.note
In a small code model,
any segment containing executable code must belong to the segment "_TEXT"
and the class "CODE".
The segment "_TEXT" must have a "combine" type of "PUBLIC".
On entry, CS contains the segment address of the segment "_TEXT".
In a big code model there is no restriction on the naming of segments
which contain executable code.
.note
In a small data model, segment register DS contains the segment address
of the group "DGROUP".
This is not the case in a big data model.
.note
When writing assembly language functions for the small code model, you
must declare them as "near".
If you wish to write assembly language functions for the big code model,
you must declare them as "far".
.note
In general, when naming segments for your code or data,
you should follow the conventions described in the section entitled
"Memory Layout" in this chapter.
.note
The caller is responsible for removing arguments from the stack.
.endnote
.do end
.*
.section Functions with Variable Number of Arguments
.*
.np
.ix 'variable argument lists'
A function prototype with a parameter list that ends with ",..."
has a variable number of arguments.
In this case, all arguments are passed on the stack.
Since no prototyping information exists for arguments represented by
",...", those arguments are passed as described in the section
"Passing Arguments".
.*
.section Returning Values from Functions
.*
.np
The way in which function values are returned depends on the size of
the return value.
The following examples describe how function values are to be returned.
They are coded for a small code model.
.ix 'functions' 'returning values'
.ix 'returning values from functions'
.autonote
.note
1-byte values are to be returned in register AL.
.exam begin
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public Ret1_
Ret1_ proc near ; char Ret1()
mov AL,'G'
ret
Ret1_ endp
_TEXT ends
end
.exam end
.note
2-byte values are to be returned in register AX.
.exam begin
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public Ret2_
Ret2_ proc near ; short int Ret2()
mov AX,77
ret
Ret2_ endp
_TEXT ends
end
.exam end
.if '&machine' eq '8086' .do begin
.note
4-byte values are to be returned in registers DX and AX with the most
significant word in register DX.
.exam begin
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public Ret4_
Ret4_ proc near ; long int Ret4()
mov AX,word ptr CS:Val4+0
mov DX,word ptr CS:Val4+2
ret
Val4 dd 7777777
Ret4_ endp
_TEXT ends
end
.exam end
.note
8-byte values, except structures, are to be returned in registers AX, BX,
CX and DX with the most significant word in register AX.
.exam begin
.8087
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public Ret8_
Ret8_ proc near ; double Ret8()
mov DX,word ptr CS:Val8+0
mov CX,word ptr CS:Val8+2
mov BX,word ptr CS:Val8+4
mov AX,word ptr CS:Val8+6
ret
Val8: dq 7.7
Ret8_ endp
_TEXT ends
end
.exam end
.np
The ".8087" pseudo-op must be specified so that all floating-point
constants are generated in 8087 format.
When using the "fpc" (floating-point calls) option, "float" and "double"
are returned in registers.
See section "Returning Values in 80x87-based Applications" when using
the "fpi" or "fpi87" options.
.do end
.el .do begin
.note
4-byte values are to be returned in register EAX.
.exam begin
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public Ret4_
Ret4_ proc near ; int Ret4()
mov EAX,7777777
ret
Ret4_ endp
_TEXT ends
end
.exam end
.note
8-byte values, except structures, are to be returned in registers
EDX and EAX.
When using the "fpc" (floating-point calls) option, "float" and "double"
are returned in registers.
See section "Returning Values in 80x87-based Applications" when using
the "fpi" or "fpi87" options.
.exam begin
.8087
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public Ret8_
Ret8_ proc near ; double Ret8()
mov EDX,dword ptr CS:Val8+4
mov EAX,dword ptr CS:Val8
ret
Val8: dq 7.7
Ret8_ endp
_TEXT ends
end
.exam end
.np
The ".8087" pseudo-op must be specified so that all floating-point
constants are generated in 8087 format.
.do end
.note
Otherwise, the caller allocates space on the stack for the return value
and sets register &siup to point to this area.
In a big data model, register &siup contains an offset relative
to the segment value in segment register SS.
.if '&machine' eq '8086' .do begin
:set symbol="word" value="word".
.do end
.el .do begin
:set symbol="word" value="dword".
.do end
.cp 19
.exam begin
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public RetX_
;
; struct int_values {
; int value1, value2, value3, value4, value5;
; };
;
RetX_ proc near ; struct int_values RetX()
mov &word ptr SS:0[&siup],71
mov &word ptr SS:4[&siup],72
mov &word ptr SS:8[&siup],73
mov &word ptr SS:12[&siup],74
mov &word ptr SS:16[&siup],75
ret
RetX_ endp
_TEXT ends
end
.exam end
.np
When returning values on the stack, remember to use a segment override
to the stack segment (SS).
.endnote
.pc
The following is an example of a &cmpname program calling the above
assembly language subprograms.
.keep 12
.millust begin
#include <stdio.h>
struct int_values {
int value1;
int value2;
int value3;
int value4;
int value5;
};
.millust break
extern char Ret1(void);
extern short int Ret2(void);
extern long int Ret4(void);
extern double Ret8(void);
extern struct int_values RetX(void);
.millust break
void main()
{
struct int_values x;
printf( "Ret1 = %c\n", Ret1() );
printf( "Ret2 = %d\n", Ret2() );
printf( "Ret4 = %ld\n", Ret4() );
printf( "Ret8 = %f\n", Ret8() );
x = RetX();
printf( "RetX1 = %d\n", x.value1 );
printf( "RetX2 = %d\n", x.value2 );
printf( "RetX3 = %d\n", x.value3 );
printf( "RetX4 = %d\n", x.value4 );
printf( "RetX5 = %d\n", x.value5 );
}
.millust end
.pc
The above function should be compiled for a small code model (use the
.if '&machine' eq '8086' .do begin
"ms" or "mc" compiler option).
.do end
.el .do begin
"mf", "ms" or "mc" compiler option).
.do end
.if '&machine' eq '80386' .do begin
.remark
.ix 'stack-based calling convention' 'returning values from functions'
.ix 'options' 'fpc'
Returning values from functions in the stack-based calling convention
is the same as returning values from functions in the register-based
calling convention when using the "fpc" option.
.eremark
.do end
.endlevel
.*
.section Calling Conventions for 80x87-based Applications
.*
.np
.ix 'passing arguments' 'in 80x87-based applications'
When a source file is compiled by &cmpname with one of the
"fpi" or "fpi87"
options, all floating-point arguments are passed on the 80x86 stack.
The rules for passing arguments are as follows.
.autonote
.note
If the argument is not floating-point, use the procedure described
earlier in this chapter.
.note
If the argument is floating-point, it is assigned a position on the
80x86 stack.
.endnote
.if '&machine' eq '80386' .do begin
.remark
.ix 'stack-based calling convention' '80x87 considerations'
When compiling using the "fpi" or "fpi87" options, the method used for
passing floating-point arguments in the stack-based calling convention
is identical to the method used in the register-based calling
convention.
However, when compiling using the "fpi" or "fpi87" options, the method
used for returning floating-point values in the stack-based calling
convention is different from the method used in the register-based
calling convention.
The register-based calling convention returns floating-point values in
ST(0), whereas the stack-based calling convention returns
floating-point values in EDX and EAX.
.eremark
.do end
.*
.beglevel
.*
.section Passing Values in 80x87-based Applications
.*
.np
.ix 'conventions' '80x87'
Consider the following example.
.cp 15
.exam begin
extern void myrtn(int,float,double,long int);
void main()
{
float x;
double y;
int i;
long int j;
x = 7.7;
i = 7;
y = 77.77
j = 77;
myrtn( i, x, y, j );
}
.exam end
.pc
.id myrtn
is an assembly language function that requires four arguments.
The first argument is of type "int" ( &intsize bytes),
the second argument is of type "float" (4 bytes),
the third argument is of type "double" (8 bytes)
and the fourth argument is of type "long int" (4 bytes).
.if '&machine' eq '8086' .do begin
These arguments will be passed to
.do end
.el .do begin
.np
When using the stack-based calling conventions, all of the arguments
will be passed on the stack.
When using the register-based calling conventions, the above arguments
will be passed to
.do end
.id myrtn
in the following way:
.autonote
.note
The first argument will be passed in register &axup leaving &bxup,
&cxup and &dxup as available registers for other arguments.
.note
The second argument will be passed on the 80x86 stack since it is a
floating-point argument.
.note
The third argument will also be passed on the 80x86 stack
since it is a floating-point argument.
.note
The fourth argument will be passed on the 80x86 stack since a previous
argument has been assigned a position on the 80x86 stack.
.endnote
.pc
Remember, arguments are pushed on the stack from right to
left.
That is, the rightmost argument is pushed first.
.np
Any assembly language function must obey the following rule.
.autonote
.note
All arguments passed on the stack must be removed by the called function.
.endnote
.np
The following is a sample assembly language function which
implements
.id myrtn.
.cp 13
.exam begin
.8087
_TEXT segment byte public 'CODE'
assume CS:_TEXT
public myrtn_
myrtn_ proc near
;
; body of function
;
ret 16 ; return and pop arguments
myrtn_ endp
_TEXT ends
end
.exam end
.autonote Notes:
.note
Function names must be followed by an underscore.
.note
All used 80x86 registers must be saved on entry and restored on exit
except those used to pass arguments and return values.
.ix 'options' 'r'
Note that segment registers only have to saved and restored if you are
compiling your application with the "r" option.
In this example, &axup does not have to be saved as it was
used to pass the first argument.
Floating-point registers can be modified without saving their contents.
.note
The direction flag must be clear before returning to the caller.
.note
This function has been written for a small code model.
Any segment containing executable code must belong to the class "CODE"
and the segment "_TEXT".
On entry, CS contains the segment address of the segment "_TEXT".
The above restrictions do not apply in a big code memory model.
.note
When writing assembly language functions for a small code model, you
must declare them as "near".
If you wish to write assembly language functions for a big code model,
you must declare them as "far".
.endnote
.*
.section Returning Values in 80x87-based Applications
.*
.np
.ix 'conventions' '80x87'
.if '&machine' eq '8086' .do begin
Floating-point values are returned in ST(0) when using the "fpi" or
"fpi87" options.
.do end
.el .do begin
When using the stack-based calling conventions with "fpi" or "fpi87",
floating-point values are returned in registers.
Single precision values are returned in EAX, and double precision
values are returned in EDX:EAX.
.np
When using the register-based calling conventions with "fpi" or
"fpi87", floating-point values are returned in ST(0).
.do end
All other values are returned in the manner described earlier in this
chapter.
.endlevel
.*
.if &e'&dohelp eq 1 .do begin
. .if '&machine' eq '8086' .do begin
. . .helppref
. .do end
. .el .do begin
. . .helppref
. .do end
.do end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -