C言語ソース
demo.c
#include <stdio.h>
int add(int c, int d) {
return c + d;
}
int main() {
int a = 10;
int b = 20;
int result = add(10, 20);
if (a > b) {
printf("a is greater\n");
} else {
printf("b is greater\n");
}
return 0;
}
生成されたアセンブリ
以下のコマンドを使って、それぞれの環境でアセンブリを生成しました:
tcc -S -IC:\TC\INCLUDE yourfile.c #msdos tarbo c
gcc -S -masm=intel demo.c -o demo.asm #win10 gcc
msdos
demo.asm
ifndef ??version
?debug macro
endm
endif
?debug S "demo.c"
_TEXT segment byte public 'CODE'
DGROUP group _DATA,_BSS
assume cs:_TEXT,ds:DGROUP,ss:DGROUP
_TEXT ends
_DATA segment word public 'DATA'
d@ label byte
d@w label word
_DATA ends
_BSS segment word public 'BSS'
b@ label byte
b@w label word
?debug C E9206AAA5A0664656D6F2E63
?debug C E9807E493115433A5C74635C696E636C7564655C737464696F2E68
?debug C E9807E493116433A5C74635C696E636C7564655C7374646172672E+
?debug C 68
_BSS ends
_TEXT segment byte public 'CODE'
; ?debug L 3
_add proc near
push bp
mov bp,sp
; ?debug L 4
mov ax,word ptr [bp+4]
add ax,word ptr [bp+6]
jmp short @1
@1:
; ?debug L 5
pop bp
ret
_add endp
; ?debug L 7
_main proc near
push bp
mov bp,sp
sub sp,2
push si
push di
; ?debug L 8
mov si,10
; ?debug L 9
mov di,20
; ?debug L 10
mov ax,20
push ax
mov ax,10
push ax
call near ptr _add
pop cx
pop cx
mov word ptr [bp-2],ax
; ?debug L 12
cmp si,di
jle @3
; ?debug L 13
mov ax,offset DGROUP:s@
push ax
call near ptr _printf
pop cx
; ?debug L 14
jmp short @4
@3:
; ?debug L 15
mov ax,offset DGROUP:s@+14
push ax
call near ptr _printf
pop cx
@4:
; ?debug L 18
xor ax,ax
jmp short @2
@2:
; ?debug L 19
pop di
pop si
mov sp,bp
pop bp
ret
_main endp
_TEXT ends
?debug C E9
_DATA segment word public 'DATA'
s@ label byte
db 97
db 32
db 105
db 115
db 32
db 103
db 114
db 101
db 97
db 116
db 101
db 114
db 10
db 0
db 98
db 32
db 105
db 115
db 32
db 103
db 114
db 101
db 97
db 116
db 101
db 114
db 10
db 0
_DATA ends
_TEXT segment byte public 'CODE'
extrn _printf:near
_TEXT ends
public _main
public _add
end
win10
demo.asm
.file "demo.c"
.intel_syntax noprefix
.text
.globl add
.def add; .scl 2; .type 32; .endef
.seh_proc add
add:
push rbp
.seh_pushreg rbp
mov rbp, rsp
.seh_setframe rbp, 0
.seh_endprologue
mov DWORD PTR 16[rbp], ecx
mov DWORD PTR 24[rbp], edx
mov edx, DWORD PTR 16[rbp]
mov eax, DWORD PTR 24[rbp]
add eax, edx
pop rbp
ret
.seh_endproc
.section .rdata,"dr"
.LC0:
.ascii "a is greater\0"
.LC1:
.ascii "b is greater\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
push rbp
.seh_pushreg rbp
mov rbp, rsp
.seh_setframe rbp, 0
sub rsp, 48
.seh_stackalloc 48
.seh_endprologue
call __main
mov DWORD PTR -4[rbp], 10
mov DWORD PTR -8[rbp], 20
mov edx, 20
mov ecx, 10
call add
mov DWORD PTR -12[rbp], eax
mov eax, DWORD PTR -4[rbp]
cmp eax, DWORD PTR -8[rbp]
jle .L4
lea rax, .LC0[rip]
mov rcx, rax
call puts
jmp .L5
.L4:
lea rax, .LC1[rip]
mov rcx, rax
call puts
.L5:
mov eax, 0
add rsp, 48
pop rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.ident "GCC: (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r3) 14.2.0"
.def puts; .scl 2; .type 32; .endef
差異
引数の渡し方
add(10, 20)
の呼び出し部分における引数の渡し方は、MS-DOS環境とWindows環境で異なります。
MS-DOS (Turbo C) では、引数は スタック に積まれまれています
msdos.s
mov ax,20
push ax
mov ax,10
push ax
call near ptr _add
Windows (GCC) では、引数は レジスタ(ecx, edx) を使って渡されています
win10.s
mov edx, 20
mov ecx, 10
call add
printfの呼び出し
win10ではputsを呼び出しています
一方、Turbo Cでは明示的に_printfが呼び出されています:
(文字列に書式指定(%dなど)が含まれていないため、GCCが最適化してputsに置き換えた??)
msdos.s
mov ax,offset DGROUP:s@
push ax
call near ptr _printf
win10.s
lea rax, .LC0[rip]
mov rcx, rax
call puts
intの大きさ
return c + d
の部分を比較すると、それぞれの環境でint型の扱いが異なることが分かります。
MS-DOS (16bit) では、ax(16ビットレジスタ)を使用している
msdos.s
mov ax,word ptr [bp+4]
add ax,word ptr [bp+6]
Windows10では、eax(32ビットレジスタ)を使用している
win10.s
mov DWORD PTR 16[rbp], ecx
mov DWORD PTR 24[rbp], edx
mov edx, DWORD PTR 16[rbp]
mov eax, DWORD PTR 24[rbp]
add eax, edx
これにより、MS-DOS環境ではintが2バイト、Windows環境では4バイトとして扱われていることが確認できます。
動作環境
MS DOS 6.22
Turbo C 2.0
Windows10 (10.0.19045.5737)
gcc version 14.2.0