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

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

ただいまの
回答率

90.75%

  • C

    3448questions

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

  • GCC

    134questions

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

  • アセンブリ言語

    102questions

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

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

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 484

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

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)

//sample0.c
#include <stdio.h>


int main (void)
{

return 0;

}
#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
//sample1.c
#include <stdio.h>


int main (void)
{
    int a = 1;
    int b = 2;
    int c = 3;

    return a + b + c;
}
#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
//sample2.c
#include <stdio.h>


int main ()
{
    int a = 2;
    int b = 3;
    int c = 4;

    return a + b + c;
}
#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
//sample3.c
#include <stdio.h>


int foo()
{
    int a = 2;
    int b = 3;
    int c = 4;

    return a + b + c;
}
#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
//sample4.c
#include <stdio.h>

int foo();

int main(void){
    return foo();
}

int foo()
{
    int a = 3;
    int b = 4;
    int c = 5;

    return a + b + c;
}
#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を公開します。

//sample5.c
#include <stdio.h>



int main(void){
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    int e = 5;
    return a+b+c+d+e;
}
#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
//sample6.c
#include <stdio.h>



int main(void){
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    int e = 5;
    int f = 6;
    return a+b+c+d+e+f;
}
#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
//sample7.c
#include <stdio.h>


int foo();

int main(void){
    int a = 1;
    int b = 2;
    int c = 3;
    int d = foo();
    int e = 5;
    int f = 6;
    return a+b+c+d+e+f;
}


int foo(){
    return 100;
}
#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
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/22 11:57

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

    キャンセル

  • 2017/11/22 12:01

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

    キャンセル

  • 2017/11/22 12:16

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

    キャンセル

  • 2017/11/22 12:52

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

    キャンセル

0

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

int foo()
{
    int a = 0;
    int b = 0;
    int c = 0;

    return a + b + c;
}
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/21 12:35

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

    キャンセル

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

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Arduino M0 Pro, ESP-WROOM-02, MILKCOCOAの接続後→ブラウザでデ...

    前提・実現したいこと 前回質問させていただいた、「Arduino M0 Pro, ESP-WROOM-02, MILKCOCOAの接続完了→ データのブラウザ表示」 (http

  • 解決済

    ダイナミックリンカローダーについて

    ダイナミックリンカローダについてです。 動的なリンカ 動的なリンカ/ローダ ELFファイルフォーマットの先頭には _startがあります。.textセクションに入っているやつで

  • 解決済

    ボタンをクリックして表示される文字列を条件分岐して表示させたい

    テキストボックスに数値を入力して、その値によって文字列を表示したいです。 しかし、どの値を入れても、最初の条件にマッチし、「軽すぎ」としか表示されません。 おまけに、formタグの

  • 解決済

    ページ上部にスクロール設定について

    ページの右下に、クリックするとページ上部に行く設定をしたのですが、スクロール位置を1000以下にすると非表示に設定をhead内に記述したのですが実行できません。 ご教授頂けますと嬉

  • 解決済

    justify-contentが効かない

    前提・実現したいこと ruby on railsで教材を参考にしながらサイトを作っています。 発生している問題・エラーメッセージ justify-contentが効かない なぜ

  • 解決済

    C++でメンバ関数をクラス外の関数から呼び出す方法 on Arduino

    ArduinoのattachInterruptにメンバー関数を割り当てる方法について質問です。 このページの回答を参考に test_class.ino #include "te

  • 解決済

    アセンブリプログラムの解説

    アセンブリ言語のプルグラムに関する質問です。 ある本でアセンブリを勉強をしているのですがわからない部分があります。 横幅が4の倍数協会にない場合のダミーデータを計算するようなのです

  • 解決済

    javaでHTMLファイルを分析

    javaでHTMLのファイルを読みだして財務分析をして流動比率というものを調べたいのですが普通に計算したほうが早いのはわかっているのですが、javaでやりたいです! これは読み

同じタグがついた質問を見る

  • C

    3448questions

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

  • GCC

    134questions

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

  • アセンブリ言語

    102questions

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