質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

Q&A

解決済

2回答

2290閲覧

アセンブリ言語の"movl $0, -4(%ebp)"とは?

takuan_no_hito

総合スコア27

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

1グッド

4クリップ

投稿2017/11/19 05:14

編集2017/11/22 01:47

アセンブリ初学者です。
アセンブリをより深く理解したく質問したしだいです。

gcc -S で吐かれたアセンブリコードを見て、以下のような記述がありました

_main: pushl %ebp movl %esp, %ebp subl $24, %esp movl $0, -4(%ebp) movl $0, -8(%ebp) movl $0, -12(%ebp) movl $0, -16(%ebp)

開始直後。

メモリ(low)
←%esp(1)
←%ebp(1)
メモリ(high)

push %ebp
の後

メモリ(low)
%ebp(1)←%esp(2)
←%esp(1)
←%ebp(1)
メモリ(high)

movl %esp, %ebp
の後

メモリ(low)
%ebp(1)←%esp(2) ←%ebp(2)
←%esp(1)
←%ebp(1)
メモリ(high)

subl $24, %esp
の後

メモリ(low)
←%esp(3)
%ebp(1)←%esp(2) ←%ebp(2)
←%esp(1)
←%ebp(1)
メモリ(high)

movl $0, -4(%ebp)
movl $0, -8(%ebp)
movl $0, -12(%ebp)
movl $0, -16(%ebp)
の後

メモリ(low)
←%esp(3)
0-16(%ebp)
0-12(%ebp)
0-8(%ebp)
0-4(%ebp)
%ebp(1)←%esp(2) ←%ebp(2)
←%esp(1)
←%ebp(1)
メモリ(high)

以降もアセンブリコードは続きますが、略。

質問

  • アセンブリコード全文を見てみると、ggc -Sが吐いたコードにおいて、(私が見た中では)必ず
movl $0, -4(%ebp) ##関数などがあると値はズレる

が書かれています。しかし、この値は0で初期化されているにも関わらず、最後まで一度も呼ばれず、使われることもありません。少なくとも私がC言語で宣言した変数ではなさそうです。return値ではないかと疑っても見ましたが、結局分からず。
この値は何のために存在するのでしょう?

ちなみに、-8(%ebp)、-12(%ebp)...は私が宣言した順に変数として使われていることは確認しました。

  • また、%ebp(1)から%esp(1)の間には一般的に何があるのでしょう。%esp(2)より上しか使っていないように見えるのですが。

Thanks

補足

以下にC言語のsampleコード及びそれに対応するアセンブリコードを5つ記します。
コマンドは
gcc -m32 -S sample.c
です。
(gcc,i386,OS X)

C

1//sample0.c 2#include <stdio.h> 3 4 5int main (void) 6{ 7 8return 0; 9 10}
#sample0.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp pushl %eax xorl %eax, %eax movl $0, -4(%ebp) addl $4, %esp popl %ebp retl .subsections_via_symbols

C

1//sample1.c 2#include <stdio.h> 3 4 5int main (void) 6{ 7 int a = 1; 8 int b = 2; 9 int c = 3; 10 11 return a + b + c; 12}
#sample1.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $16, %esp movl $0, -4(%ebp) movl $1, -8(%ebp) movl $2, -12(%ebp) movl $3, -16(%ebp) movl -8(%ebp), %eax addl -12(%ebp), %eax addl -16(%ebp), %eax addl $16, %esp popl %ebp retl .subsections_via_symbols

C

1//sample2.c 2#include <stdio.h> 3 4 5int main () 6{ 7 int a = 2; 8 int b = 3; 9 int c = 4; 10 11 return a + b + c; 12}
#sample2.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $16, %esp movl $0, -4(%ebp) movl $2, -8(%ebp) movl $3, -12(%ebp) movl $4, -16(%ebp) movl -8(%ebp), %eax addl -12(%ebp), %eax addl -16(%ebp), %eax addl $16, %esp popl %ebp retl .subsections_via_symbols

C

1//sample3.c 2#include <stdio.h> 3 4 5int foo() 6{ 7 int a = 2; 8 int b = 3; 9 int c = 4; 10 11 return a + b + c; 12}
#sample3.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _foo .p2align 4, 0x90 _foo: ## @foo ## BB#0: pushl %ebp movl %esp, %ebp subl $12, %esp movl $2, -4(%ebp) movl $3, -8(%ebp) movl $4, -12(%ebp) movl -4(%ebp), %eax addl -8(%ebp), %eax addl -12(%ebp), %eax addl $12, %esp popl %ebp retl .subsections_via_symbols

C

1//sample4.c 2#include <stdio.h> 3 4int foo(); 5 6int main(void){ 7 return foo(); 8} 9 10int foo() 11{ 12 int a = 3; 13 int b = 4; 14 int c = 5; 15 16 return a + b + c; 17}
#sample4.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $8, %esp movl $0, -4(%ebp) calll _foo addl $8, %esp popl %ebp retl .globl _foo .p2align 4, 0x90 _foo: ## @foo ## BB#0: pushl %ebp movl %esp, %ebp subl $12, %esp movl $3, -4(%ebp) movl $4, -8(%ebp) movl $5, -12(%ebp) movl -4(%ebp), %eax addl -8(%ebp), %eax addl -12(%ebp), %eax addl $12, %esp popl %ebp retl .subsections_via_symbols

コードの追加

ちなみに、-4(%ebp)の部分を詰めて、例えばsample3.sを以下のように書き換えても、プログラムは動きます。ここでは%espを引く値も変えていますが、変えなくても当然動きます。

#sample2.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $12, %esp movl $2, -4(%ebp) movl $3, -8(%ebp) movl $4, -12(%ebp) movl -4(%ebp), %eax addl -8(%ebp), %eax addl -12(%ebp), %eax addl $12, %esp popl %ebp retl .subsections_via_symbols

新たにsample5~sample8を公開します。

C

1//sample5.c 2#include <stdio.h> 3 4 5 6int main(void){ 7 int a = 1; 8 int b = 2; 9 int c = 3; 10 int d = 4; 11 int e = 5; 12 return a+b+c+d+e; 13}
#sample5.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $24, %esp movl $0, -4(%ebp) movl $1, -8(%ebp) movl $2, -12(%ebp) movl $3, -16(%ebp) movl $4, -20(%ebp) movl $5, -24(%ebp) movl -8(%ebp), %eax addl -12(%ebp), %eax addl -16(%ebp), %eax addl -20(%ebp), %eax addl -24(%ebp), %eax addl $24, %esp popl %ebp retl .subsections_via_symbols

C

1//sample6.c 2#include <stdio.h> 3 4 5 6int main(void){ 7 int a = 1; 8 int b = 2; 9 int c = 3; 10 int d = 4; 11 int e = 5; 12 int f = 6; 13 return a+b+c+d+e+f; 14}
#sample7.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $28, %esp movl $0, -4(%ebp) movl $1, -8(%ebp) movl $2, -12(%ebp) movl $3, -16(%ebp) movl $4, -20(%ebp) movl $5, -24(%ebp) movl $6, -28(%ebp) movl -8(%ebp), %eax addl -12(%ebp), %eax addl -16(%ebp), %eax addl -20(%ebp), %eax addl -24(%ebp), %eax addl -28(%ebp), %eax addl $28, %esp popl %ebp retl .subsections_via_symbols

C

1//sample7.c 2#include <stdio.h> 3 4 5int foo(); 6 7int main(void){ 8 int a = 1; 9 int b = 2; 10 int c = 3; 11 int d = foo(); 12 int e = 5; 13 int f = 6; 14 return a+b+c+d+e+f; 15} 16 17 18int foo(){ 19 return 100; 20}
#sample7.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $40, %esp movl $0, -4(%ebp) movl $1, -8(%ebp) movl $2, -12(%ebp) movl $3, -16(%ebp) calll _foo movl %eax, -20(%ebp) movl $5, -24(%ebp) movl $6, -28(%ebp) movl -8(%ebp), %eax addl -12(%ebp), %eax addl -16(%ebp), %eax addl -20(%ebp), %eax addl -24(%ebp), %eax addl -28(%ebp), %eax addl $40, %esp popl %ebp retl .globl _foo .p2align 4, 0x90 _foo: ## @foo ## BB#0: pushl %ebp movl %esp, %ebp movl $100, %eax popl %ebp retl .subsections_via_symbols
//sample8.c #include <stdio.h> int foo(); int main(void){ int a = 1; int b = 2; int d = foo(); int e = 5; int f = 6; return a+b+d+e+f; } int foo(){ return 100; }
#sample8.s .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _main .p2align 4, 0x90 _main: ## @main ## BB#0: pushl %ebp movl %esp, %ebp subl $24, %esp movl $0, -4(%ebp) movl $1, -8(%ebp) movl $2, -12(%ebp) calll _foo movl %eax, -16(%ebp) movl $5, -20(%ebp) movl $6, -24(%ebp) movl -8(%ebp), %eax addl -12(%ebp), %eax addl -16(%ebp), %eax addl -20(%ebp), %eax addl -24(%ebp), %eax addl $24, %esp popl %ebp retl .globl _foo .p2align 4, 0x90 _foo: ## @foo ## BB#0: pushl %ebp movl %esp, %ebp movl $100, %eax popl %ebp retl .subsections_via_symbols
Magkinh👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

最適化したら消えないですか?

投稿2017/11/22 02:27

fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuan_no_hito

2017/11/22 02:57

回答ありがとうございます。 少し複雑なコードで試してみたところ、確かに消えるようです。 しかし、最適化云々は別にして、何か理由あってこのような構造にしているのではないのでしょうか? できればそれが知りたいのです。
fuzzball

2017/11/22 03:01

スタックオーバーフローのチェック用かな、と思ったりもしましたが。 最適化していない状態の無駄コードの存在理由を調べることに意味があるとは思えません。
takuan_no_hito

2017/11/22 03:16

いつもあって不思議に思っていたので。 意味がないならないで良いのですが。
fuzzball

2017/11/22 03:52

コンパイラ自体に興味があって調べているのであれば、意味はあると思います。 コンパイル結果にしか興味が無いなら、意味は無いでしょう。
guest

0

以下のソースをからアセンブラソースを生成すると以下のようになります。

C

1int foo() 2{ 3 int a = 0; 4 int b = 0; 5 int c = 0; 6 7 return a + b + c; 8}
pushl %ebp movl %esp, %ebp subl $16, %esp movl $0, -4(%ebp) movl $0, -8(%ebp) movl $0, -12(%ebp) movl -4(%ebp), %edx movl -8(%ebp), %eax addl %eax, %edx movl -12(%ebp), %eax addl %edx, %eax leave ret

このように特に無駄な領域は取られていません。

そちらの元のC言語のソースに問題があるのではないでしょうか。

また、「%ebp(1)から%esp(1)の間」には、呼び出し元に戻るためのリターンアドレスがあります


追記

私も読み違えていましたが、私が提示したアセンブラソースでも1ワード分、スタックに余りがありました。

subl $16, %esp

これは、スタックポインタを16byte境界で動かすためで、intの変数を5つ使うようにすると、スタックは32byte取られるようになり、8byteは未使用になります。

但し、私の環境(Ubuntu 17.04、gcc 6.3.0)では、sample2.cは以下のようになります。

pushl %ebp movl %esp, %ebp subl $16, %esp call __x86.get_pc_thunk.ax addl $_GLOBAL_OFFSET_TABLE_, %eax movl $2, -12(%ebp) movl $3, -8(%ebp) movl $4, -4(%ebp) movl -12(%ebp), %edx movl -8(%ebp), %eax addl %eax, %edx movl -4(%ebp), %eax addl %edx, %eax leave ret __x86.get_pc_thunk.ax: movl (%esp), %eax ret

そちらの環境では、未使用領域を0で初期化しているようですが、こちらではなりません。

使用する変数の数を変化させてコードを生成すれば、より情報が得られるかもしれません。

投稿2017/11/20 08:53

編集2017/11/21 05:36
Harahira

総合スコア243

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuan_no_hito

2017/11/21 03:35

回答ありがとうございます。 確かにmain関数でなければ、当方でもこの現象は起きていないようですが、main関数内では必ず(?)存在するようです。補足にいくつかC言語とそれに対応するアセンブリコードを書いてみましたので、よろしければ見ていただきたく。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問