__stdcall呼び出し規約:
int foo1(int a) { return a * 2; } int foo2(int a, int b) { return a + b; } int foo3(int a, int b, int c) { return a + b + c; } int foo4(int a, int b, int c, int d) { return a + b + c + d; }
#include <stdio.h> extern int foo1(int a); extern int foo2(int a, int b); extern int foo3(int a, int b, int c); extern int foo4(int a, int b, int c, int d); int __cdecl main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(10)); printf("foo2() = %d\n", foo2(10, 20)); printf("foo3() = %d\n", foo3(10, 20, 30)); printf("foo4() = %d\n", foo4(10, 20, 30, 40)); return 0; }
int __stdcall foobar(); typedef int (__stdcall *ptr)();
コンパイル&リンク&実行
> cl /FAs /TC /Od /nologo /c /Gz /Focallee_stdcall.obj callee.c > cl /FAs /TC /Od /nologo /c /Gz /Focaller_stdcall.obj caller.c > link /SUBSYSTEM:CONSOLE /NOLOGO /OUT:stdcall.exe caller_stdcall.obj callee_stdcall.obj > stdcall.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100
; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01
TITLE C:\in_vitro\c\calling_conventions\callee.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC _foo1@4
; Function compile flags: /Odtp
; File c:\in_vitro\c\calling_conventions\callee.c
_TEXT SEGMENT
_a$ = 8 ; size = 4
_foo1@4 PROC
; 1 : int foo1(int a) { return a * 2; }
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
shl eax, 1
pop ebp
ret 4
_foo1@4 ENDP
_TEXT ENDS
PUBLIC _foo2@8
; Function compile flags: /Odtp
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_foo2@8 PROC
; 2 : int foo2(int a, int b) { return a + b; }
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
add eax, DWORD PTR _b$[ebp]
pop ebp
ret 8
_foo2@8 ENDP
_TEXT ENDS
PUBLIC _foo3@12
; Function compile flags: /Odtp
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_foo3@12 PROC
; 3 : int foo3(int a, int b, int c) { return a + b + c; }
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
add eax, DWORD PTR _b$[ebp]
add eax, DWORD PTR _c$[ebp]
pop ebp
ret 12 ; 0000000cH
_foo3@12 ENDP
_TEXT ENDS
PUBLIC _foo4@16
; Function compile flags: /Odtp
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_d$ = 20 ; size = 4
_foo4@16 PROC
; 4 : int foo4(int a, int b, int c, int d) { return a + b + c + d; }
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
add eax, DWORD PTR _b$[ebp]
add eax, DWORD PTR _c$[ebp]
add eax, DWORD PTR _d$[ebp]
pop ebp
ret 16 ; 00000010H
_foo4@16 ENDP
_TEXT ENDS
END
; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01
TITLE C:\in_vitro\c\calling_conventions\caller.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
_DATA SEGMENT
$SG2496 DB 'foo1() = %d', 0aH, 00H
ORG $+3
$SG2497 DB 'foo2() = %d', 0aH, 00H
ORG $+3
$SG2498 DB 'foo3() = %d', 0aH, 00H
ORG $+3
$SG2499 DB 'foo4() = %d', 0aH, 00H
_DATA ENDS
PUBLIC _main
EXTRN _foo4@16:PROC
EXTRN _foo3@12:PROC
EXTRN _foo2@8:PROC
EXTRN _printf:PROC
EXTRN _foo1@4:PROC
; Function compile flags: /Odtp
; File c:\in_vitro\c\calling_conventions\caller.c
_TEXT SEGMENT
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_main PROC
; 9 : {
push ebp
mov ebp, esp
; 10 : printf("foo1() = %d\n", foo1(10));
push 10 ; 0000000aH
call _foo1@4
push eax
push OFFSET $SG2496
call _printf
add esp, 8
; 11 : printf("foo2() = %d\n", foo2(10, 20));
push 20 ; 00000014H
push 10 ; 0000000aH
call _foo2@8
push eax
push OFFSET $SG2497
call _printf
add esp, 8
; 12 : printf("foo3() = %d\n", foo3(10, 20, 30));
push 30 ; 0000001eH
push 20 ; 00000014H
push 10 ; 0000000aH
call _foo3@12
push eax
push OFFSET $SG2498
call _printf
add esp, 8
; 13 : printf("foo4() = %d\n", foo4(10, 20, 30, 40));
push 40 ; 00000028H
push 30 ; 0000001eH
push 20 ; 00000014H
push 10 ; 0000000aH
call _foo4@16
push eax
push OFFSET $SG2499
call _printf
add esp, 8
; 14 : return 0;
xor eax, eax
; 15 : }
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
int __stdcall foobar(); typedef int (__stdcall *ptr)();
アセンブラコードを生成
> bcc32 -ps -S callee.c > bcc32 -ps -S caller.c
コンパイル&リンク&実行
> bcc32 -ps -c -ocallee_stdcall.obj callee.c > bcc32 -ps -c -ocaller_stdcall.obj caller.c > ilink32 /c /ap /Tpe c0x32 caller_stdcall callee_stdcall, stdcall, , cw32 import32 > stdcall.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100
.386p
ifdef ??version
if ??version GT 500H
.mmx
endif
endif
model flat
ifndef ??version
?debug macro
endm
endif
?debug S "callee.c"
?debug T "callee.c"
_TEXT segment dword public use32 'CODE'
_TEXT ends
_DATA segment dword public use32 'DATA'
_DATA ends
_BSS segment dword public use32 'BSS'
_BSS ends
DGROUP group _BSS,_DATA
_TEXT segment dword public use32 'CODE'
foo1 proc near
?live1@0:
;
; int foo1(int a) { return a * 2; }
;
push ebp
mov ebp,esp
@1:
mov eax,dword ptr [ebp+8]
add eax,eax
@3:
@2:
pop ebp
ret 4
foo1 endp
foo2 proc near
?live1@32:
;
; int foo2(int a, int b) { return a + b; }
;
push ebp
mov ebp,esp
@4:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
@6:
@5:
pop ebp
ret 8
foo2 endp
foo3 proc near
?live1@64:
;
; int foo3(int a, int b, int c) { return a + b + c; }
;
push ebp
mov ebp,esp
@7:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
add eax,dword ptr [ebp+16]
@9:
@8:
pop ebp
ret 12
foo3 endp
foo4 proc near
?live1@96:
;
; int foo4(int a, int b, int c, int d) { return a + b + c + d; }
;
push ebp
mov ebp,esp
@10:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
add eax,dword ptr [ebp+16]
add eax,dword ptr [ebp+20]
@12:
@11:
pop ebp
ret 16
foo4 endp
_TEXT ends
public foo1
public foo2
public foo3
public foo4
?debug D "callee.c" 15473 24064
end
.386p
ifdef ??version
if ??version GT 500H
.mmx
endif
endif
model flat
ifndef ??version
?debug macro
endm
endif
?debug S "caller.c"
?debug T "caller.c"
_TEXT segment dword public use32 'CODE'
_TEXT ends
_DATA segment dword public use32 'DATA'
_DATA ends
_BSS segment dword public use32 'BSS'
_BSS ends
DGROUP group _BSS,_DATA
_TEXT segment dword public use32 'CODE'
_main proc near
?live1@0:
;
; int __cdecl main(int argc, char *argv[])
;
push ebp
mov ebp,esp
;
; {
; printf("foo1() = %d\n", foo1(10));
;
@1:
push 10
call foo1
push eax
push offset s@
call _printf
add esp,8
;
; printf("foo2() = %d\n", foo2(10, 20));
;
push 20
push 10
call foo2
push eax
push offset s@+13
call _printf
add esp,8
;
; printf("foo3() = %d\n", foo3(10, 20, 30));
;
push 30
push 20
push 10
call foo3
push eax
push offset s@+26
call _printf
add esp,8
;
; printf("foo4() = %d\n", foo4(10, 20, 30, 40));
;
push 40
push 30
push 20
push 10
call foo4
push eax
push offset s@+39
call _printf
add esp,8
;
; return 0;
;
xor eax,eax
;
; }
;
@3:
@2:
pop ebp
ret
_main endp
_TEXT ends
_DATA segment dword public use32 'DATA'
s@ label byte
; s@+0:
db "foo1() = %d",10,0
; s@+13:
db "foo2() = %d",10,0
; s@+26:
db "foo3() = %d",10,0
; s@+39:
db "foo4() = %d",10,0
align 4
_DATA ends
_TEXT segment dword public use32 'CODE'
_TEXT ends
public _main
extrn __setargv__:near
extrn _printf:near
extrn foo1:near
extrn foo2:near
extrn foo3:near
extrn foo4:near
?debug D "C:\in_vitro\apps\borland\bcc55\include\_nfile.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\_null.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\_defs.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\_stddef.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\stdio.h" 10339 10240
?debug D "caller.c" 15473 24232
end
※サンプルコードは C言語系/呼び出し規約/x86/fortran の callee.c, caller.c を使用。
int __stdcall foobar(); typedef int (__stdcall *ptr)();
コンパイル&リンク&実行
> wcc -od -d0 -ecd callee.c > wcc -od -d0 -ecd caller.c > wcl -fe=stdcall16.exe caller.obj callee.obj > stdcall16.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 foo5() = 150 foo6() = 210
アセンブラ生成
> wdis -a -l=callee.asm callee.obj > wdis -a -l=caller.asm caller.obj
.387
PUBLIC _foo1
PUBLIC _foo2
PUBLIC _foo3
PUBLIC _foo4
PUBLIC _foo5
PUBLIC _foo6
EXTRN __STK:BYTE
EXTRN _small_code_:BYTE
DGROUP GROUP CONST,CONST2,_DATA
_TEXT SEGMENT BYTE PUBLIC USE16 'CODE'
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP
_foo1:
mov ax,4
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 4[bp]
shl ax,1
pop bp
ret 2
_foo2:
mov ax,4
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 4[bp]
add ax,word ptr 6[bp]
pop bp
ret 4
_foo3:
mov ax,4
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 4[bp]
add ax,word ptr 6[bp]
add ax,word ptr 8[bp]
pop bp
ret 6
_foo4:
mov ax,4
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 4[bp]
add ax,word ptr 6[bp]
add ax,word ptr 8[bp]
add ax,word ptr 0aH[bp]
pop bp
ret 8
_foo5:
mov ax,4
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 4[bp]
add ax,word ptr 6[bp]
add ax,word ptr 8[bp]
add ax,word ptr 0aH[bp]
add ax,word ptr 0cH[bp]
pop bp
ret 0aH
_foo6:
mov ax,4
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 4[bp]
add ax,word ptr 6[bp]
add ax,word ptr 8[bp]
add ax,word ptr 0aH[bp]
add ax,word ptr 0cH[bp]
add ax,word ptr 0eH[bp]
pop bp
ret 0cH
_TEXT ENDS
CONST SEGMENT WORD PUBLIC USE16 'DATA'
CONST ENDS
CONST2 SEGMENT WORD PUBLIC USE16 'DATA'
CONST2 ENDS
_DATA SEGMENT WORD PUBLIC USE16 'DATA'
_DATA ENDS
END
.387
PUBLIC main_
EXTRN __STK:BYTE
EXTRN _foo1:BYTE
EXTRN printf_:BYTE
EXTRN _foo2:BYTE
EXTRN _foo3:BYTE
EXTRN _foo4:BYTE
EXTRN _foo5:BYTE
EXTRN _foo6:BYTE
EXTRN __argc:BYTE
EXTRN _small_code_:BYTE
EXTRN _cstart_:BYTE
DGROUP GROUP CONST,CONST2,_DATA
_TEXT SEGMENT BYTE PUBLIC USE16 'CODE'
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP
main_:
push ax
mov ax,12H
call near ptr __STK
pop ax
push bx
push cx
mov ax,0aH
push ax
call near ptr _foo1
push ax
mov ax,offset DGROUP:L$1
push ax
call near ptr printf_
add sp,4
mov ax,14H
push ax
mov ax,0aH
push ax
call near ptr _foo2
push ax
mov ax,offset DGROUP:L$2
push ax
call near ptr printf_
add sp,4
mov ax,1eH
push ax
mov ax,14H
push ax
mov ax,0aH
push ax
call near ptr _foo3
push ax
mov ax,offset DGROUP:L$3
push ax
call near ptr printf_
add sp,4
mov ax,28H
push ax
mov ax,1eH
push ax
mov ax,14H
push ax
mov ax,0aH
push ax
call near ptr _foo4
push ax
mov ax,offset DGROUP:L$4
push ax
call near ptr printf_
add sp,4
mov ax,32H
push ax
mov ax,28H
push ax
mov ax,1eH
push ax
mov ax,14H
push ax
mov ax,0aH
push ax
call near ptr _foo5
push ax
mov ax,offset DGROUP:L$5
push ax
call near ptr printf_
add sp,4
mov ax,3cH
push ax
mov ax,32H
push ax
mov ax,28H
push ax
mov ax,1eH
push ax
mov ax,14H
push ax
mov ax,0aH
push ax
call near ptr _foo6
push ax
mov ax,offset DGROUP:L$6
push ax
call near ptr printf_
add sp,4
xor ax,ax
pop cx
pop bx
ret
_TEXT ENDS
CONST SEGMENT WORD PUBLIC USE16 'DATA'
L$1:
DB 66H, 6fH, 6fH, 31H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$2:
DB 66H, 6fH, 6fH, 32H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$3:
DB 66H, 6fH, 6fH, 33H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$4:
DB 66H, 6fH, 6fH, 34H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$5:
DB 66H, 6fH, 6fH, 35H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$6:
DB 66H, 6fH, 6fH, 36H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
CONST ENDS
CONST2 SEGMENT WORD PUBLIC USE16 'DATA'
CONST2 ENDS
_DATA SEGMENT WORD PUBLIC USE16 'DATA'
_DATA ENDS
END
※サンプルコードは C言語系/呼び出し規約/x86/fortran の callee.c, caller.c を使用。
int __stdcall foobar(); typedef int (__stdcall *ptr)();
コンパイル&リンク&実行
> wcc386 -od -d0 -ecd callee.c > wcc386 -od -d0 -ecd caller.c > wcl386 -fe=stdcall32.exe caller.obj callee.obj > stdcall32.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 foo5() = 150 foo6() = 210
アセンブラ生成
> wdis -a -l=callee.asm callee.obj > wdis -a -l=caller.asm caller.obj
.387
.386p
.model flat
PUBLIC `_foo1@4`
PUBLIC `_foo2@8`
PUBLIC `_foo3@12`
PUBLIC `_foo4@16`
PUBLIC `_foo5@20`
PUBLIC `_foo6@24`
EXTRN __CHK:BYTE
DGROUP GROUP CONST,CONST2,_DATA
_TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP
`_foo1@4`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,eax
ret 4
`_foo2@8`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,dword ptr 8[esp]
ret 8
`_foo3@12`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,dword ptr 8[esp]
add eax,dword ptr 0cH[esp]
ret 0cH
`_foo4@16`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,dword ptr 8[esp]
add eax,dword ptr 0cH[esp]
add eax,dword ptr 10H[esp]
ret 10H
`_foo5@20`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,dword ptr 8[esp]
add eax,dword ptr 0cH[esp]
add eax,dword ptr 10H[esp]
add eax,dword ptr 14H[esp]
ret 14H
`_foo6@24`:
push 4
call near ptr FLAT:__CHK
mov eax,dword ptr 4[esp]
add eax,dword ptr 8[esp]
add eax,dword ptr 0cH[esp]
add eax,dword ptr 10H[esp]
add eax,dword ptr 14H[esp]
add eax,dword ptr 18H[esp]
ret 18H
_TEXT ENDS
CONST SEGMENT DWORD PUBLIC USE32 'DATA'
CONST ENDS
CONST2 SEGMENT DWORD PUBLIC USE32 'DATA'
CONST2 ENDS
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
_DATA ENDS
END
.387
.386p
.model flat
PUBLIC main_
EXTRN __CHK:BYTE
EXTRN `_foo1@4`:BYTE
EXTRN printf_:BYTE
EXTRN `_foo2@8`:BYTE
EXTRN `_foo3@12`:BYTE
EXTRN `_foo4@16`:BYTE
EXTRN `_foo5@20`:BYTE
EXTRN `_foo6@24`:BYTE
EXTRN __argc:BYTE
EXTRN _cstart_:BYTE
DGROUP GROUP CONST,CONST2,_DATA
_TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP
main_:
push 20H
call near ptr FLAT:__CHK
push ecx
push 0aH
call near ptr FLAT:`_foo1@4`
push eax
push offset FLAT:L$1
call near ptr FLAT:printf_
add esp,8
push 14H
push 0aH
call near ptr FLAT:`_foo2@8`
push eax
push offset FLAT:L$2
call near ptr FLAT:printf_
add esp,8
push 1eH
push 14H
push 0aH
call near ptr FLAT:`_foo3@12`
push eax
push offset FLAT:L$3
call near ptr FLAT:printf_
add esp,8
push 28H
push 1eH
push 14H
push 0aH
call near ptr FLAT:`_foo4@16`
push eax
push offset FLAT:L$4
call near ptr FLAT:printf_
add esp,8
push 32H
push 28H
push 1eH
push 14H
push 0aH
call near ptr FLAT:`_foo5@20`
push eax
push offset FLAT:L$5
call near ptr FLAT:printf_
add esp,8
push 3cH
push 32H
push 28H
push 1eH
push 14H
push 0aH
call near ptr FLAT:`_foo6@24`
push eax
push offset FLAT:L$6
call near ptr FLAT:printf_
add esp,8
xor eax,eax
pop ecx
ret
_TEXT ENDS
CONST SEGMENT DWORD PUBLIC USE32 'DATA'
L$1:
DB 66H, 6fH, 6fH, 31H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$2:
DB 66H, 6fH, 6fH, 32H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$3:
DB 66H, 6fH, 6fH, 33H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$4:
DB 66H, 6fH, 6fH, 34H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$5:
DB 66H, 6fH, 6fH, 35H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$6:
DB 66H, 6fH, 6fH, 36H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
CONST ENDS
CONST2 SEGMENT DWORD PUBLIC USE32 'DATA'
CONST2 ENDS
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
_DATA ENDS
END
MinGWおよびLinuxのgcc用のサンプルコード。"CALLINGCONV"をコンパイルオプションで実行時に指定して、呼び出し規約を切り替える。
int __attribute__((CALLINGCONV)) foo1(int a) { return a * 2; } int __attribute__((CALLINGCONV)) foo2(int a, int b) { return a + b; } int __attribute__((CALLINGCONV)) foo3(int a, int b, int c) { return a + b + c; } int __attribute__((CALLINGCONV)) foo4(int a, int b, int c, int d) { return a + b + c + d; } int __attribute__((CALLINGCONV)) foo5(int a, int b, int c, int d, int e) { return a + b + c + d + e; }
#include <stdio.h> extern int __attribute__((CALLINGCONV)) foo1(int a); extern int __attribute__((CALLINGCONV)) foo2(int a, int b); extern int __attribute__((CALLINGCONV)) foo3(int a, int b, int c); extern int __attribute__((CALLINGCONV)) foo4(int a, int b, int c, int d); extern int __attribute__((CALLINGCONV)) foo5(int a, int b, int c, int d, int e); int __attribute__((cdecl)) main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(10)); printf("foo2() = %d\n", foo2(10, 20)); printf("foo3() = %d\n", foo3(10, 20, 30)); printf("foo4() = %d\n", foo4(10, 20, 30, 40)); printf("foo5() = %d\n", foo5(10, 20, 30, 40, 50)); return 0; }
"__attribute__" を使うか、"__stdcall" を使う。なお "__stdcall" はプリプロセス時に "__attribute__" 版に変換される。
int __stdcall foo(); →プリプロセス後 int __attribute__((stdcall)) foo();
コンパイル&リンク&実行
$ gcc -O0 -Wall --save-temps -DCALLINGCONV=stdcall -c callee.c $ gcc -O0 -Wall --save-temps -DCALLINGCONV=stdcall -c caller.c $ gcc -o stdcall caller.o callee.o $ stdcall.exe foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 foo5() = 150
.file "callee.c" .text .globl _foo1@4 .def _foo1@4; .scl 2; .type 32; .endef _foo1@4: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax addl %eax, %eax popl %ebp ret $4 .globl _foo2@8 .def _foo2@8; .scl 2; .type 32; .endef _foo2@8: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax popl %ebp ret $8 .globl _foo3@12 .def _foo3@12; .scl 2; .type 32; .endef _foo3@12: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax popl %ebp ret $12 .globl _foo4@16 .def _foo4@16; .scl 2; .type 32; .endef _foo4@16: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax addl 20(%ebp), %eax popl %ebp ret $16 .globl _foo5@20 .def _foo5@20; .scl 2; .type 32; .endef _foo5@20: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax addl 20(%ebp), %eax addl 24(%ebp), %eax popl %ebp ret $20
.file "caller.c" .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "foo1() = %d\12\0" LC1: .ascii "foo2() = %d\12\0" LC2: .ascii "foo3() = %d\12\0" LC3: .ascii "foo4() = %d\12\0" LC4: .ascii "foo5() = %d\12\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax call __alloca call ___main movl $10, (%esp) call _foo1@4 subl $4, %esp movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl $20, 4(%esp) movl $10, (%esp) call _foo2@8 subl $8, %esp movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call _foo3@12 subl $12, %esp movl %eax, 4(%esp) movl $LC2, (%esp) call _printf movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call _foo4@16 subl $16, %esp movl %eax, 4(%esp) movl $LC3, (%esp) call _printf movl $50, 16(%esp) movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call _foo5@20 subl $20, %esp movl %eax, 4(%esp) movl $LC4, (%esp) call _printf movl $0, %eax leave ret .def _foo5@20; .scl 2; .type 32; .endef .def _foo4@16; .scl 2; .type 32; .endef .def _foo3@12; .scl 2; .type 32; .endef .def _foo2@8; .scl 2; .type 32; .endef .def _foo1@4; .scl 2; .type 32; .endef .def _printf; .scl 2; .type 32; .endef
int __attribute__((stdcall)) foo();
コンパイル&リンク&実行
$ gcc -O0 -Wall --save-temps -DCALLINGCONV=stdcall -c callee.c $ gcc -O0 -Wall --save-temps -DCALLINGCONV=stdcall -c caller.c $ gcc -o stdcall caller.o callee.o $ ./stdcall foo1() = 20 foo2() = 30 foo3() = 60 foo4() = 100 foo5() = 150
.file "callee.c" .text .globl foo1 .type foo1, @function foo1: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax addl %eax, %eax popl %ebp ret $4 .size foo1, .-foo1 .globl foo2 .type foo2, @function foo2: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax popl %ebp ret $8 .size foo2, .-foo2 .globl foo3 .type foo3, @function foo3: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax popl %ebp ret $12 .size foo3, .-foo3 .globl foo4 .type foo4, @function foo4: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax addl 20(%ebp), %eax popl %ebp ret $16 .size foo4, .-foo4 .globl foo5 .type foo5, @function foo5: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax addl 16(%ebp), %eax addl 20(%ebp), %eax addl 24(%ebp), %eax popl %ebp ret $20 .size foo5, .-foo5 .ident "GCC: (GNU) 4.1.2 20071124 (Red Hat 4.1.2-42)" .section .note.GNU-stack,"",@progbits
.file "caller.c" .section .rodata .LC0: .string "foo1() = %d\n" .LC1: .string "foo2() = %d\n" .LC2: .string "foo3() = %d\n" .LC3: .string "foo4() = %d\n" .LC4: .string "foo5() = %d\n" .text .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $20, %esp movl $10, (%esp) call foo1 subl $4, %esp movl %eax, 4(%esp) movl $.LC0, (%esp) call printf movl $20, 4(%esp) movl $10, (%esp) call foo2 subl $8, %esp movl %eax, 4(%esp) movl $.LC1, (%esp) call printf movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call foo3 subl $12, %esp movl %eax, 4(%esp) movl $.LC2, (%esp) call printf movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call foo4 subl $16, %esp movl %eax, 4(%esp) movl $.LC3, (%esp) call printf movl $50, 16(%esp) movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call foo5 subl $20, %esp movl %eax, 4(%esp) movl $.LC4, (%esp) call printf movl $0, %eax movl -4(%ebp), %ecx leave leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (GNU) 4.1.2 20071124 (Red Hat 4.1.2-42)" .section .note.GNU-stack,"",@progbits