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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

5回答

4001閲覧

アセンブリの基本を教えてください

haya-linux

総合スコア23

C

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

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

3クリップ

投稿2017/03/26 15:00

編集2017/03/27 06:24

c言語のアセンブリの基本について教えてください。
質問は#のあとに書いてあります。
よろしくお願いします。

CPU他情報
description: Computer
width: 32 bits
*-core
description: Motherboard
physical id: 0
*-memory
description: System memory
physical id: 0
size: 1988MiB

Architecture: i686
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 15
Model name: Intel(R) Core(TM)2 Duo CPU L7100 @ 1.20GHz
Stepping: 11
CPU MHz: 1201.000
CPU max MHz: 1201.0000
CPU min MHz: 800.0000
BogoMIPS: 2394.07
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 4096K

ソース
#include <stdio.h>

int main()
{
int i;
for (i=0; i<10; i++)
{
printf("Hello, World!\n");
}
return 0;

}

コマンド
gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2)
$ gcc -o firstprog firstprog.c
$ objdump -D firstprog | grep -A70 main.:

0804840b <main>:
1 804840b: 8d 4c 24 04 lea 0x4(%esp),%ecx
2 804840f: 83 e4 f0 and $0xfffffff0,%esp #なぜこれをしないといけないのか?
3 8048412: ff 71 fc pushl -0x4(%ecx) ##これと対になるのはなにか?
4 8048415: 55 push %ebp
5 8048416: 89 e5 mov %esp,%ebp
6 8048418: 51 push %ecx ##これと対になるのはなにか?
7 8048419: 83 ec 14 sub $0x14,%esp ##なぜ10行目があるのに、これをしないといけないのか?
8 804841c: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%ebp)
9 8048423: eb 14 jmp 8048439 <main+0x2e>
10 8048425: 83 ec 0c sub $0xc,%esp
11 8048428: 68 d0 84 04 08 push $0x80484d0
12 804842d: e8 ae fe ff ff call 80482e0 puts@plt
13 8048432: 83 c4 10 add $0x10,%esp
14 8048435: 83 45 f4 01 addl $0x1,-0xc(%ebp)
15 8048439: 83 7d f4 09 cmpl $0x9,-0xc(%ebp)
16 804843d: 7e e6 jle 8048425 <main+0x1a>
17 804843f: b8 00 00 00 00 mov $0x0,%eax ##これはなにをしてるのか?
18 8048444: 8b 4d fc mov -0x4(%ebp),%ecx##これはなにをしてるのか?
19 8048447: c9 leave
20 8048448: 8d 61 fc lea -0x4(%ecx),%esp
21 804844b: c3 ret

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

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

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

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

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

ikedas

2017/03/27 03:41

元のCのソースコードも示して下さい。また、アセンブラの種類、対象アーキテクチャも明記していただけませんか。
guest

回答5

0

そんなに詳しいわけではないのですが、読み解いてみました。なお、回答時点では元のCのソースコードを参照できなかったため、処理の詳細について認識違いがあるかもしれません。

1 804840b: 8d 4c 24 04 lea 0x4(%esp),%ecx 2 804840f: 83 e4 f0 and $0xfffffff0,%esp #なぜこれをしないといけないのか?

こうする理由のひとつは、スタックの位置をキャッシュラインサイズに合わせるためだと思います。スタックがキャッシュラインサイズ (x86では64バイト) の境界をまたぐように配置されると、スタック操作の際にキャッシュミスが多発して速度が落ちます。スタックを16バイト境界に揃えれば、速度低下を回避しやすくなります。が、なぜ最大の64バイト境界で揃えないのかはわかりません (メモリの節約のためでしょうか)。

もうひとつ。SSE命令では128ビットのレジスタを使う関係から、全てのデータが16バイト境界にそろえてある必要があります。スタックもこれに合わせて、4バイトや8バイトではなく16バイト境界で揃えているのだと考えられます。

いずれにせよ、スタックポインタを書き換えてしまうとretしたときに呼び出し元に戻れません。書き換える前に、スタック最上部に積んであるもの (戻り先のアドレス) のアドレス0x4(%esp)を、%ecxに保存しています。

投稿2017/03/27 04:39

編集2017/03/27 05:08
ikedas

総合スコア4335

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

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

sharow

2017/03/27 10:17

> %ecxを積む意味は私には分かりません。 これはmainの第一引数のアドレスです。main()に引数がありそれをつかっている場合には、破壊されていなければ%ecxを、破壊されていればこの積まれた値を経由して使います。 アドレス相対0x1Cにある戻り先のアドレスをpushしている意味は私にも謎です。これは使われていませんし、というかこれを使って戻ってしまうと呼び出し側にとってesp破壊です。もしかすると__builtin_return_address()のようなgcc拡張がmain()で使われたときとかに関係するのかも・・。
ikedas

2017/03/27 12:09

なるほど! 引数のことを忘れていました。なんで4を足したり引いたりしているのかと不思議でしたが、確かにこのアドレスは必要ですね。 使われない戻り先アドレスも謎ですが、sharowさんがおっしゃるようなことかもしれませんね。スタートアップスタブやライブラリ関数はスタックのアライメント調整をやってくれない (そういうことを考慮していない) ようですから、辻褄合わせが必要なのかも知れません。
guest

0

こんにちは。

全部は分からないので、解る部分だけ回答してみます。

2 804840f: 83 e4 f0 and $0xfffffff0,%esp #なぜこれをしないといけないのか?

ローカル変数のアライメントを調整してローカル変数アクセス速度を最適化することが目的です。
自作エミュレータで学ぶx86アーキテクチャ: コンピュータが動く仕組みを徹底理解!の立ち読みできる部分にも解説がありました。(この本、解りやすそうな感じがします。)

7 8048419: 83 ec 14 sub $0x14,%esp ##なぜ10行目があるのに、これをしないといけないのか?

main()関数の一番外側のブロックで有効なローカル変数領域の確保ではないかと思います。
そして、恐らくfor()ループがあるのではないでしょうか? 10行目はそのforループ内で確保しているローカル変数領域の確保ではないかと思います。

6 8048418: 51 push %ecx ##これと対になるのはなにか?

この直前でmov %esp,%ebpしているので、6行目終了時、ebp-4のアドレスにecxが記録されています。下記にてecxを回復しているのだと思います。

18 8048444: 8b 4d fc mov -0x4(%ebp),%ecx##これはなにをしてるのか?

17 804843f: b8 00 00 00 00 mov $0x0,%eax ##これはなにをしてるのか?

return 0;の0を設定しているのではないかと思います。
関数の戻り値を返却する際にeaxを使うことは良くあります。

80x86系のアセンブラは大昔に少し触っただけなので外していたらごめんなさい。

投稿2017/03/27 03:16

Chironian

総合スコア23272

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

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

0

ご質問のストレートな回答ではないことをお断りしておきます。
アセンブラのプログラミングに当たっては、構文の理解もさることながらレジスタ、メモリ(アドレス)、スタックに関する概念と1部ハードウエアについても理解が必要です。ご質問のような部分的な疑問について回答を得たとしても、謎はさらに深まる恐れが有ります。要領良く理解するケースも無いとは言えませんが。
参考書などお探しになって、体系的に理解することをお勧めします。
自分はZ80(30年以上前ですが)で参考書を何度も読み返して習得し、ハード設計とファームウェアを書きましたがかなりの学習コストを要しました。今の本で紹介できるものに心当たりが無くて済みません。
ご参考までに。

投稿2017/03/27 02:52

BlueMoon

総合スコア1339

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

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

0

0804840b <main>:
1 804840b: 8d 4c 24 04 lea 0x4(%esp),%ecx
2 804840f: 83 e4 f0 and $0xfffffff0,%esp #なぜこれをしないといけないのか?
3 8048412: ff 71 fc pushl -0x4(%ecx) ##これと対になるのはなにか? →多分、18行ではないのでしょうか?
4 8048415: 55 push %ebp
5 8048416: 89 e5 mov %esp,%ebp
6 8048418: 51 push %ecx ##これと対になるのはなにか?
7 8048419: 83 ec 14 sub $0x14,%esp
8 804841c: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%ebp)
9 8048423: eb 14 jmp 8048439 <main+0x2e>
10 8048425: 83 ec 0c sub $0xc,%esp
11 8048428: 68 d0 84 04 08 push $0x80484d0
12 804842d: e8 ae fe ff ff call 80482e0 puts@plt
13 8048432: 83 c4 10 add $0x10,%esp ##これをするとesp-0x14とesp-0x16の間にアドレス空間ができてしまう気がするのですが?
14 8048435: 83 45 f4 01 addl $0x1,-0xc(%ebp)
15 8048439: 83 7d f4 09 cmpl $0x9,-0xc(%ebp)
16 804843d: 7e e6 jle 8048425 <main+0x1a>
17 804843f: b8 00 00 00 00 mov $0x0,%eax ##これはreturn 0でしょうか?
18 8048444: 8b 4d fc mov -0x4(%ebp),%ecx##これはなにをしてるのか? 多分3行目とついになってのでは?
19 8048447: c9 leave
20 8048448: 8d 61 fc lea -0x4(%ecx),%esp
21 804844b: c3 ret

投稿2017/03/26 17:08

編集2017/03/26 17:23
haya-linux

総合スコア23

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

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

0

自分はきちんとした知識を持ってないので個別にちゃんとした解説はできませんが、読み解くうえで参考になるだろう事項があるのでコメントしてみます。これらについてどこかによい教科書なり解説記事なりがあると学びやすいと思いますが、残念ながら自分は知りません。(性能上気になる点を確認するためにアセンブリーソースを見る程度ですので、本格的な知識は持ってないのです)

  • スタックフレームとは何か(そもそもスタックマシンとはなにか)

Cでmain関数から関数fを呼んでそこからgを読んで・・・という具合にし、各関数の引数やローカル変数のアドレスを調べると大まかなイメージがつかめます。スタックフレームはコンパイラーの種類によって色々変わりますので「このコンパイラーはこういうスタックフレームにしているようだ」というあたりを付けつつコードを見るとよいと思います。
おそらくC/C++プログラマーの方は(詳細さにばらつきはあるにせよ)スタックフレームがどういう構造かは知っている方も多いと思います。というのはメモリー破壊のデバッグの際に知るはめになるからです。

  • 各レジスターの役割

今日よく目にするのはx64(?)などと思いますが、espはスタックポインターでebpはフレームポインターというのを知っておけば理解しやすいと思います。C++だとthisがどのレジスターに載っているかなども意識するとよいかと思います。

  • コンパイルの最適化

最適化レベルが変わると効率が悪い機械語コードがよりよいものに変わります。それを踏まえて読むとよいかも知れません。「なんか無駄なコードがでてる」と思ったとき最適化レベルを変えてコンパイルすることでどのくらい賢い機械語コードに変化するかが観察できると思います。(最適化されすぎて読めなくなることも・・・)

  • プロセッサの初歩的な知識

時折不自然な順番で命令が並んでいるように見えることがあります。しかしプロセッサが命令をパイプラインで実行していると知っていれば多少不自然にみえても「まぁそういう事情なのだろう」で済ませることができます。しかし本当にアセンブリー言語でバリバリに書こうとする人ならプロセッサーのアーキテクチャーを詳しく知り「なぜこういう順番にするとパイプラインがうまく動くのか」を把握した上で読んだり・書いたりするのかも知れませんね。しかしカーネルプログラミングのようにプロセッサのより詳しい仕様を知らないと全然歯がたたないものもありますね。自分はせいぜい「システムコールはソフトウェア割り込み命令なのかな?」という程度しか知りません。

質問者さんの目的にもよるでしょうが、上に書いた程度を学ぶとそこそこの役には立つ気がします。

投稿2017/03/26 17:24

編集2017/03/27 00:13
KSwordOfHaste

総合スコア18394

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

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

Zuishin

2017/03/26 22:30

矛盾した順番でコマンドが並ぶことがあるのですか? 例えばどういうものでしょう?
KSwordOfHaste

2017/03/27 00:20 編集

「矛盾」じゃなく「不自然」というべきでした。矛盾した順番で並んでいてはおかしいですね!ご指摘ありがとうございます。 --- 自分が書こうとしたのはCでの式や文に対する機械語命令がC上で書かれている順番に必ずしも並ばないことがあるというようなことです。
Zuishin

2017/03/27 01:11

アセンブラではなく C ソースをコンパイルした際に、パイプラインを考慮した最適化によって命令が前後するという意味でしょうか? どうも私が読み違えていたようです。ありがとうございました。
KSwordOfHaste

2017/03/27 03:40

> パイプラインを考慮した最適化によって命令が前後するという意味 そういうものをイメージしていました。自分の表現は適切ではなかったですね。Zuishinさんの表現が端的にポイントをついているように感じました。 (レジスター・メモリー・ALUなどのアクセスの衝突をなるべく避ける目的でうまいこと順番を入れかている・・・というようなことを書こうとしたのですがどうも自身なくて、簡単な表現に改めようとしたものの結局変な説明になってしまってました。申し訳ないです。)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問