0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

同一Cソースから生成されたアセンブリの比較:MS-DOS版Turbo CとWindows版GCCの違い

Posted at

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

image.png

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?