"WINAPI", "CALLBACK", "APIENTRY"はヘッダーファイルで定義された呼び出し規約で、実際にどの呼び出し規約("__stdcall", "__cdecl", "__pascal", ...)になるかは OS/コンパイラによって異なってくるので、使用する場合は注意が必要。
ただし、2010年現在の Win32 APIプラットフォームにおいては基本的にどれも "__stdcall" と考えて良い。
VC++2008, Borland C++ Compiler, OpenWatcom(32bit), MinGW-gcc 共に、この3つは"__stdcall"にdefineされている。
WINAPI, CALLBACK, APIENTRY はWin32API用なので、使うにはWindows用のヘッダーファイルをincludeする必要がある。今回は "windows.h" をincludeした。
#include <stdio.h> #include <windows.h> int WINAPI foo1(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int CALLBACK foo2(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int APIENTRY foo3(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5)); printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0)); printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50)); return 0; }
プリプロセス結果およびアセンブラ出力から、"__stdcall" にdefineされている事が分かる。
コンパイル&リンク&実行
> cl /FAs /TC /Od /nologo /c winapis.c > link /SUBSYSTEM:CONSOLE /NOLOGO /OUT:winapis.exe winapis.obj > winapis.exe foo1() = 15 foo2() = 30 foo3() = 150
プリプロセス結果を生成:
> cl /P /TC /Od /nologo /c winapis.c
プリプロセス結果:
#line 3 "winapis.c" int __stdcall foo1(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __stdcall foo2(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __stdcall foo3(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5)); printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0)); printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50)); return 0; }
; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01
TITLE C:\in_vitro\c\cc_vc\winapis.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
_DATA SEGMENT
$SG78612 DB 'foo1() = %d', 0aH, 00H
ORG $+3
$SG78613 DB 'foo2() = %d', 0aH, 00H
ORG $+3
$SG78614 DB 'foo3() = %d', 0aH, 00H
_DATA ENDS
PUBLIC _foo1@20
; Function compile flags: /Odtp
; File c:\in_vitro\c\cc_vc\winapis.c
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_d$ = 20 ; size = 4
_e$ = 24 ; size = 4
_foo1@20 PROC
; 6 : { return a + b + c + d + e; }
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]
add eax, DWORD PTR _e$[ebp]
pop ebp
ret 20 ; 00000014H
_foo1@20 ENDP
_TEXT ENDS
PUBLIC _foo2@20
; Function compile flags: /Odtp
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_d$ = 20 ; size = 4
_e$ = 24 ; size = 4
_foo2@20 PROC
; 10 : { return a + b + c + d + e; }
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]
add eax, DWORD PTR _e$[ebp]
pop ebp
ret 20 ; 00000014H
_foo2@20 ENDP
_TEXT ENDS
PUBLIC _foo3@20
; Function compile flags: /Odtp
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_d$ = 20 ; size = 4
_e$ = 24 ; size = 4
_foo3@20 PROC
; 14 : { return a + b + c + d + e; }
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]
add eax, DWORD PTR _e$[ebp]
pop ebp
ret 20 ; 00000014H
_foo3@20 ENDP
_TEXT ENDS
PUBLIC _main
EXTRN _printf:PROC
; Function compile flags: /Odtp
_TEXT SEGMENT
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_main PROC
; 16 : int main(int argc, char *argv[]) {
push ebp
mov ebp, esp
; 17 : printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5));
push 5
push 4
push 3
push 2
push 1
call _foo1@20
push eax
push OFFSET $SG78612
call _printf
add esp, 8
; 18 : printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0));
push 0
push 9
push 8
push 7
push 6
call _foo2@20
push eax
push OFFSET $SG78613
call _printf
add esp, 8
; 19 : printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50));
push 50 ; 00000032H
push 40 ; 00000028H
push 30 ; 0000001eH
push 20 ; 00000014H
push 10 ; 0000000aH
call _foo3@20
push eax
push OFFSET $SG78614
call _printf
add esp, 8
; 20 : return 0;
xor eax, eax
; 21 : }
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
プリプロセス結果およびアセンブラ出力から、"__stdcall" にdefineされている事が分かる。
アセンブラコードを生成
> bcc32 -S winapis.c
コンパイル&実行
> bcc32 winapis.c > winapis.exe foo1() = 15 foo2() = 30 foo3() = 150
プリプロセス結果を生成:
> cpp32 winapis.c
プリプロセス結果:
/* winapis.c 3: */ /* winapis.c 4: */int __stdcall /* winapis.c 5: */foo1(int a, int b, int c, int d, int e) /* winapis.c 6: */{ return a + b + c + d + e; } /* winapis.c 7: */ /* winapis.c 8: */int __stdcall /* winapis.c 9: */foo2(int a, int b, int c, int d, int e) /* winapis.c 10: */{ return a + b + c + d + e; } /* winapis.c 11: */ /* winapis.c 12: */int __stdcall /* winapis.c 13: */foo3(int a, int b, int c, int d, int e) /* winapis.c 14: */{ return a + b + c + d + e; } /* winapis.c 15: */ /* winapis.c 16: */int main(int argc, char *argv[]) { /* winapis.c 17: */printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5)); /* winapis.c 18: */printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0)); /* winapis.c 19: */printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50)); /* winapis.c 20: */return 0; /* winapis.c 21: */}
.386p
ifdef ??version
if ??version GT 500H
.mmx
endif
endif
model flat
ifndef ??version
?debug macro
endm
endif
?debug S "winapis.c"
?debug T "winapis.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:
;
; foo1(int a, int b, int c, int d, int e)
;
push ebp
mov ebp,esp
;
; { return a + b + c + d + e; }
;
@1:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
add eax,dword ptr [ebp+16]
add eax,dword ptr [ebp+20]
add eax,dword ptr [ebp+24]
@3:
@2:
pop ebp
ret 20
foo1 endp
foo2 proc near
?live1@48:
;
; foo2(int a, int b, int c, int d, int e)
;
push ebp
mov ebp,esp
;
; { return a + b + c + d + e; }
;
@4:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
add eax,dword ptr [ebp+16]
add eax,dword ptr [ebp+20]
add eax,dword ptr [ebp+24]
@6:
@5:
pop ebp
ret 20
foo2 endp
foo3 proc near
?live1@96:
;
; foo3(int a, int b, int c, int d, int e)
;
push ebp
mov ebp,esp
;
; { return a + b + c + d + e; }
;
@7:
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
add eax,dword ptr [ebp+16]
add eax,dword ptr [ebp+20]
add eax,dword ptr [ebp+24]
@9:
@8:
pop ebp
ret 20
foo3 endp
_main proc near
?live1@144:
;
; int main(int argc, char *argv[]) {
;
push ebp
mov ebp,esp
;
; printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5));
;
@10:
push 5
push 4
push 3
push 2
push 1
call foo1
push eax
push offset s@
call _printf
add esp,8
;
; printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0));
;
push 0
push 9
push 8
push 7
push 6
call foo2
push eax
push offset s@+13
call _printf
add esp,8
;
; printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50));
;
push 50
push 40
push 30
push 20
push 10
call foo3
push eax
push offset s@+26
call _printf
add esp,8
;
; return 0;
;
xor eax,eax
;
; }
;
@12:
@11:
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
align 4
_DATA ends
_TEXT segment dword public use32 'CODE'
_TEXT ends
public foo1
public foo2
public foo3
public _main
extrn __setargv__:near
extrn _printf:near
?debug C 9F757569642E6C6962
?debug C 9F757569642E6C6962
?debug D "C:\in_vitro\apps\borland\bcc55\include\imm.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mcx.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winsvc.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\commdlg.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\oleauto.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\propidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\oaidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\msxml.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\servprov.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\oleidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\urlmon.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\cguid.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\objidl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\unknwn.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\search.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\stdlib.h" 10521 10272
?debug D "C:\in_vitro\apps\borland\bcc55\include\objbase.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\ole2.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\prsht.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winspool.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winsmcrd.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winioctl.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnsip.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcndr.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wtypes.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winscard.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winefs.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wincrypt.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\qos.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winsock2.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winperf.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\shellapi.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcasync.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnterr.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcnsi.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcdcep.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpcdce.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\rpc.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\nb30.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mmsystem.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\lzexpand.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\dlgs.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\ddeml.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\dde.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\cderr.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winnetwk.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winreg.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winver.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wincon.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winnls.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\tvout.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winuser.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack1.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\wingdi.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winerror.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winbase.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack8.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack2.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\poppack.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\pshpack4.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mem.h" 10521 10272
?debug D "C:\in_vitro\apps\borland\bcc55\include\_loc.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\locale.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\_str.h" 10521 10272
?debug D "C:\in_vitro\apps\borland\bcc55\include\string.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\guiddef.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\basetsd.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\mbctype.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\ctype.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\winnt.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\windef.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\stdarg.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\excpt.h" 10339 10240
?debug D "C:\in_vitro\apps\borland\bcc55\include\windows.h" 10339 10240
?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 "winapis.c" 15473 36482
end
プリプロセス結果およびアセンブラ出力から、"WINAPI"と"CALLBACK" は "__far __pascal" にdefineされている事が分かる。
※16bit用のヘッダーファイルではAPIENTRYが未定義の為、コメントアウトして確認している。
コンパイル&リンク&実行
> set INCLUDE=%WATCOM%\h;%WATCOM%\h\win > wcl winapis.c
アセンブラ生成:
> wdis -a -l=winapis.asm winapis.obj
プリプロセス結果を生成:
> wcl -pcl -fo winapis.i winapis.c
プリプロセス結果:
#line 2 "winapis.c" int __far __pascal foo1(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __far __pascal foo2(int a, int b, int c, int d, int e) { return a + b + c + d + e; } /* int APIENTRY foo3(int a, int b, int c, int d, int e) { return a + b + c + d + e; } */ int main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5)); printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0)); /*printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50));*/ return 0; }
.387
PUBLIC FOO1
PUBLIC FOO2
PUBLIC main_
EXTRN __STK:BYTE
EXTRN printf_: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
FOO1:
mov ax,6
L$1:
call near ptr __STK
push bp
mov bp,sp
mov ax,word ptr 0eH[bp]
add ax,word ptr 0cH[bp]
add ax,word ptr 0aH[bp]
add ax,word ptr 8[bp]
add ax,word ptr 6[bp]
pop bp
retf 0aH
FOO2:
mov ax,6
jmp L$1
main_:
push ax
mov ax,10H
call near ptr __STK
pop ax
push bx
push cx
mov ax,1
push ax
mov ax,2
push ax
mov ax,3
push ax
mov ax,4
push ax
mov ax,5
push ax
push cs
call near ptr FOO1
push ax
mov ax,offset DGROUP:L$2
push ax
call near ptr printf_
add sp,4
mov ax,6
push ax
mov ax,7
push ax
mov ax,8
push ax
mov ax,9
push ax
xor ax,ax
push ax
push cs
call near ptr FOO2
push ax
mov ax,offset DGROUP:L$3
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$2:
DB 66H, 6fH, 6fH, 31H, 28H, 29H, 20H, 3dH
DB 20H, 25H, 64H, 0aH, 0
L$3:
DB 66H, 6fH, 6fH, 32H, 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
プリプロセス結果およびアセンブラ出力から、"__stdcall" にdefineされている事が分かる。
コンパイル&リンク&実行
> set INCLUDE=%WATCOM%\h;%WATCOM%\h\nt > wcl386 winapis.c
アセンブラ生成:
> wdis -a -l=winapis.asm winapis.obj
プリプロセス結果を生成:
> wcl386 -pcl -fo winapis.i winapis.c
プリプロセス結果:
#line 2 "winapis.c" int __stdcall foo1(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __stdcall foo2(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __stdcall foo3(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5)); printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0)); printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50)); return 0; }
.387
.386p
.model flat
PUBLIC `_foo1@20`
PUBLIC `_foo2@20`
PUBLIC `_foo3@20`
PUBLIC main_
EXTRN __CHK:BYTE
EXTRN printf_: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
`_foo1@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
`_foo2@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
`_foo3@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
main_:
push 1cH
call near ptr FLAT:__CHK
push ecx
push 5
push 4
push 3
push 2
push 1
call near ptr FLAT:`_foo1@20`
push eax
push offset FLAT:L$1
call near ptr FLAT:printf_
add esp,8
push 0
push 9
push 8
push 7
push 6
call near ptr FLAT:`_foo2@20`
push eax
push offset FLAT:L$2
call near ptr FLAT:printf_
add esp,8
push 32H
push 28H
push 1eH
push 14H
push 0aH
call near ptr FLAT:`_foo3@20`
push eax
push offset FLAT:L$3
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
CONST ENDS
CONST2 SEGMENT DWORD PUBLIC USE32 'DATA'
CONST2 ENDS
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
_DATA ENDS
END
プリプロセス結果およびアセンブラ出力から、"__attribute__()"版stdcall にdefineされている事が分かる。
コンパイル&リンク&実行
$ gcc -O0 -Wall --save-temps -o winapis winapis.c $ winapis.exe foo1() = 15 foo2() = 30 foo3() = 150
プリプロセス結果:
# 3 "winapis.c" 2 int __attribute__((__stdcall__)) foo1(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __attribute__((__stdcall__)) foo2(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int __attribute__((__stdcall__)) foo3(int a, int b, int c, int d, int e) { return a + b + c + d + e; } int main(int argc, char *argv[]) { printf("foo1() = %d\n", foo1(1, 2, 3, 4, 5)); printf("foo2() = %d\n", foo2(6, 7, 8, 9, 0)); printf("foo3() = %d\n", foo3(10, 20, 30, 40, 50)); return 0; }
.file "winapis.c" .text .globl _foo1@20 .def _foo1@20; .scl 2; .type 32; .endef _foo1@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 .globl _foo2@20 .def _foo2@20; .scl 2; .type 32; .endef _foo2@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 .globl _foo3@20 .def _foo3@20; .scl 2; .type 32; .endef _foo3@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 .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" .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 $5, 16(%esp) movl $4, 12(%esp) movl $3, 8(%esp) movl $2, 4(%esp) movl $1, (%esp) call _foo1@20 subl $20, %esp movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl $0, 16(%esp) movl $9, 12(%esp) movl $8, 8(%esp) movl $7, 4(%esp) movl $6, (%esp) call _foo2@20 subl $20, %esp movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $50, 16(%esp) movl $40, 12(%esp) movl $30, 8(%esp) movl $20, 4(%esp) movl $10, (%esp) call _foo3@20 subl $20, %esp movl %eax, 4(%esp) movl $LC2, (%esp) call _printf movl $0, %eax leave ret .def _printf; .scl 2; .type 32; .endef