私は約10年間、高水準言語(Python、C#、VBA、VB.NET)でプログラミングしており、「内部」で何が起こっているのかを完全に理解していません。
アセンブリを学ぶことの利点は何ですか、それはプログラマとして私をどのように助けますか?より高いレベルのコードで記述したものとアセンブリで発生することとの関係を正確に示すリソースを提供していただけませんか?
本当にがどのように機能するかを理解できるからです。
つまり、C#またはPythonで記述したものはすべて、コンピューターが実行できる一連の基本的なアクションに変換する必要があります。コンピューターを簡単に考えることができます。クラス、ジェネリックス、リスト内包のいずれかですが、これらは当社の高水準プログラミング言語にのみ存在します。
見た目は素晴らしいが、物事の低レベルの方法にうまく変換できない言語構成体を考えることができます。それが実際にどのように機能するかを知ることで、物事が彼らのように機能する理由をよりよく理解できます。
これにより、「内部で起こっていること」と、ポインタのしくみ、およびレジスタ変数とアーキテクチャの意味(メモリの割り当てと管理、パラメータの受け渡し(値による/参照による)など)の一般的な理解が深まります。
Cをざっと見てみると、どうですか?
#include <stdio.h>
main()
{
puts("Hello World.");
return(0);
}
gcc -S so.c
を使用してコンパイルし、so.s
のアセンブリ出力を確認します。
$ cat so.s
.file "so.c"
.section .rodata
.LC0:
.string "Hello World."
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits
あなたが求める答えはここにあると思います: http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language
記事からの引用:
それは本当ですが、おそらく次の顧客のアプリをアセンブリで作成していることに気付かないでしょう。アセンブリを学ぶことから得られることはまだたくさんあります。現在、アセンブリ言語は主にハードウェアの直接操作、特殊なプロセッサ命令へのアクセス、または重要なパフォーマンス問題への対処に使用されています。一般的な用途は、デバイスドライバー、低レベルの組み込みシステム、およびリアルタイムシステムです。
問題は、高水準言語が複雑になり、記述されるADT(抽象データ型)が増えるほど、これらのオプションをサポートするために発生するオーバーヘッドが増えることです。 .NETのインスタンスでは、おそらく肥大化したMSIL。 MSILを知っていると想像してみてください。これが、アセンブリ言語が優れている点です。
アセンブリ言語は、プログラマーと同じくらいプロセッサに近いので、適切に設計されたアルゴリズムは非常に優れています。アセンブリは速度の最適化に最適です。パフォーマンスと効率性がすべてです。アセンブリ言語を使用すると、システムのリソースを完全に制御できます。アセンブリラインのように、単一の値をレジスタにプッシュするコードを記述し、メモリアドレスを直接処理して値またはポインタを取得します。
アセンブリで書くことは、「物事を起こさせる」ためにプロセッサーとメモリーがどのように連携するかを正確に理解することです。注意してください、アセンブリ言語は不可解であり、アプリケーションのソースコードサイズは高級言語のものよりもはるかに大きいです。しかし、それについて間違いはありません。もしあなたがアセンブリを習得するための時間と努力を惜しみなく入れれば、あなたはより良くなり、フィールドで目立つようになります。
さらに、この本はコンピュータアーキテクチャの簡略化されたバージョンがあるため、この本をお勧めします。コンピューティングシステムの概要:ビットとゲートからCとその先へイリノイ大学アーバナ/シャンペーン校
私の控えめな意見では、それはあまり役に立ちません。
私はx86アセンブリをよく知っていました。アセンブリが私のコースで登場したとき、それは少し助けになりました、それはインタビュー中に一度現れました、そしてそれは私がコンパイラ(Metrowerks)が悪いコードを生成していたことを証明するのを助けました。コンピューターが実際にどのように機能するかは魅力的で、私はそれを学んだことで知的に豊かになったと感じています。当時はとても楽しく遊べました。
ただし、今日のコンパイラは、ほとんどすべてのコードで、ほとんど誰よりもアセンブリの生成に優れています。コンパイラーを書いている、またはコンパイラーが正しいことを行っていることを確認しているのでない限り、おそらくそれを学ぶことで時間を無駄にしています。
C++プログラマーが今でも有用に尋ねる多くの質問は、Assemblyを知ることで知らされることを認めます。たとえば、スタック変数またはヒープ変数を使用する必要がありますか?値またはconst参照で渡す必要がありますか?ただし、ほとんどすべての場合において、これらの選択は、計算時間の節約ではなく、コードの読みやすさに基づいて行われるべきだと思います。 (たとえば、変数をスコープに制限する場合は常にスタック変数を使用します。)
私の控えめな提案は、ソフトウェア設計、アルゴリズム分析、問題解決など、本当に重要なスキルに焦点を当てることです。大きなプロジェクトの開発経験があれば、あなたの直感は向上し、(私の意見では)アセンブリを知るよりもはるかに価値が高まります。
作業しているシステムの1レベル「深い」に精通している必要があります。 1回の移動でスキップしすぎることは悪くありませんが、望んでいるほど役立つとは限りません。
高水準言語のプログラマは、低水準言語を学ぶ必要があります(Cは優れたオプションです)。オブジェクトをインスタンス化したり、ハッシュテーブルやセットを作成したりするようにコンピューターに指示するときに、内部で何が行われているのかを理解するためにアセンブリに完全に行く必要はありませんが、コードを記述できるはずです。それら。
Javaプログラマーの場合、Cを学習すると、メモリ管理や引数の引き渡しに役立ちます。Cで広範なJavaライブラリを作成すると、 Setのどの実装をいつ使用するかを理解する(ハッシュが必要ですか、それともツリーですか?)スレッド環境でchar *を処理すると、Stringが不変である理由を理解するのに役立ちます。
次のレベルに進みます... Cプログラマーは、アセンブリについてある程度の知識が必要です。アセンブリタイプ(組み込みシステムショップでよく見られる)は、ゲートレベルでの理解に役立つでしょう。ゲートを扱う人は、いくつかの量子物理学を知っている必要があります。そして、それらの量子物理学者たちは、まあ、彼らはまだ次の抽象化が何であるかを理解しようとしています。
あなたが知っている言語のリストでCやC++について言及しなかったからです。私はアセンブリについて考える前にそれらをよく学ぶことを強くお勧めします。 CまたはC++は、管理された言語で完全に透過的なすべての基本的な概念を提供し、このページで説明されている概念のほとんどを、実際のプロジェクトで使用できる最も重要な言語の1つで理解します。これは、プログラミングスキルに対する真の付加価値です。アセンブリは非常に特定の領域で使用され、CまたはC++ほど有用ではないことに注意してください。
アンマネージ言語がどのように機能するかを理解する前に、Assemblyに飛び込むべきではない、と私はさらに言います。ほぼ必読です。
さらに下に行きたい場合は、アセンブリを学ぶ必要があります。言語のすべての構成要素がどのように作成されるかを正確に知りたい。それは有益ですが、それはまったく異なるレベルの複雑さです。
言語をよく知っている場合は、少なくとも技術の基本的な知識を抽象化の1レベル下に持っている必要があります。
どうして?物事がうまくいかない場合、根本的なメカニズムの知識により、奇妙な問題のデバッグがはるかに簡単になり、自然に効率的なコードを書くことができます
例としてPython(/ CPython)を使用すると、奇妙なクラッシュやパフォーマンスの低下を始めた場合、Cコードのデバッグ方法に関する知識が非常に役立ちます。これは、参照カウントメモリ管理方法に関する知識と同じです。これは、何かをCの拡張機能としていつ、またはどのように記述するかを知るのにも役立ちます。
この場合の質問に答えるために、アセンブリの知識は経験豊富なPython開発者には役立ちません(抽象化の段階が多すぎるため、Python =多くの多くのアセンブリ命令が発生します)
..しかし、Cの経験がある場合は、「次のレベルを下げる」(アセンブリ)を知っていることは実際に役立ちます。
同様に、CoffeScriptを使用している場合、Javascriptを知っていると(非常に)役立ちます。 Clojureを使用している場合は、Java/JVMの知識が役立ちます。
このアイデアは、プログラミング言語以外でも機能します。アセンブリを使用している場合は、基盤となるハードウェアの機能について理解しておくことをお勧めします。あなたがウェブデザイナーなら、ウェブアプリケーションがどのように実装されているかを知っておくことは良い考えです。あなたが自動車整備士なら、いくつかの物理学についてある程度の知識を持っていることをお勧めします
小さなcプログラムを書き、出力を逆アセンブルします。それで全部です。ただし、オペレーティングシステムの利益のために追加される多かれ少なかれ「ハウスキーピング」コードに備えてください。
アセンブリは、メモリ、プロセッサレジスタなどを直接処理するため、内部で何が行われているのかを理解するのに役立ちます。
オペレーティングシステムの複雑さをまったく複雑にせずにベアメタルに移行したい場合は、アセンブリ言語で Arduinoをプログラミングしてみてください。
プログラマーはすべてのタイプではないので、明確な答えはありません。その下に潜むものを知る必要がありますか?もしそうなら、それを学ぶ。あなたは単に好奇心からそれを学びたいだけですか?もしそうなら、それを学ぶ。それがあなたにとって実際的な利益をもたらさないなら、それならなぜわざわざ?車を運転するだけで整備士の知識が必要ですか?整備士は、自動車で作業するためだけにエンジニアの知識レベルを必要としますか?これは深刻な類推です。整備士は、維持している車両についてエンジニアが深度を理解するためのダイビングを行わなくても、非常に優れた生産的な整備士になることができます。音楽についても同じです。メロディー、ハーモニー、リズムの複雑さを上手に歌手や奏者にすることを本当に考えていますか?いいえ。例外的に才能のあるミュージシャンの中には、ドリアンとリディアンのモードの違いを言うまでもなく、一枚の楽譜を読むことができない人もいます。必要な場合は問題ありませんが、必要はありません。あなたがWeb開発者であれば、Assemblyは私が考えることができる実用的な用途はありません。あなたが組み込みシステムや本当に特別な何かをしているなら、それは必要かもしれませんが、もしそうであれば、あなたはそれを知っているでしょう。
以下は、非高水準言語を学習するというこれらの価値に対するJoelの見解です。 http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html
実際、おそらくあなたにとって最良のことは、(私の知る限りでは)どこにも存在しないクラスでしょう。それは、マシン/アセンブラ言語の簡単な概要とストレージアドレス指定の概念と、コンパイラ構築のツアーを組み合わせたクラスでしょう。 、コード生成、およびランタイム環境。
問題は、C#やPythonなどのハードウェアから遠く離れた高水準の言語では、すべての移動が数百になるという事実を本当に理解していないということです。数千の機械語命令ではなく、高水準言語の数行が膨大な量のストレージにアクセスして変更する原因となる方法を理解する傾向はありません。何が起こっているのかを正確に知る必要はそれほどありません「カバーの下」ではありますが、何が起こっているのか、そして発生するタイプの一般的な概念について理解を深める必要があります。
この質問に対する私の答えは、比較的最近になって発展しました。既存の回答は、私が過去に言っていたであろうことをカバーしています。実際、これは トップアンサー -「上位レベルのプログラミングで構造を理解する」ポイントでまだカバーされていますが、言及する価値があると思う特別なケースです...
このJeff Atwoodのブログ投稿 によると、研究を参照しているため、割り当てを理解することはプログラミングを理解する上で重要な問題です。学習者のプログラマーは、表記法がコンピューターがたどるステップとそのステップによる理由を表すだけであることを理解するか、そうでなければ、数式などの誤解を招く類推によって永久に混乱します。
さて、あなたが6502アセンブラから以下を理解しているなら...
LDA variable
CLC
ADC #1
STA variable
それはほんのステップです。次に、それを代入文に変換することを学ぶとき...
variable = variable + 1;
数式の誤解を招く類推は必要ありません。マップするための正しいメンタルモデルがすでにあります。
[〜#〜] edit [〜#〜]-もちろん、もしあなたがLDA variable
は基本的にACCUMULATOR = variable
は、いくつかのチュートリアルやリファレンスから得られるものであり、開始した場所に戻ってしまい、まったく役に立ちません。
私は2番目の言語として6502アセンブラーを学びました。1つ目はCommodore Basicでしたが、その当時はあまり学習していませんでした。これは、学ぶことがほとんどなかったためと、当時はアセンブラーが非常に興味深いように思えたためです。 。 14歳のオタクであったこともあり、時代もありました。
私がやったことをすることはお勧めしませんが、非常に単純なアセンブラー言語でいくつかの非常に単純な例を研究することは、高水準言語を学ぶための価値のある予備知識になるのではないかと思います。
詳細(レジスタの割り当てなど)の量が原因で、アセンブリを記述しても、魔法のような速度の向上はありません。おそらく、これまでで最も簡単なアルゴリズムを記述します。
さらに、最新の(読み取り-70-80年代以降に設計された)プロセッサーでは、アセンブリは何が起こっているのかを知るのに十分な数の詳細を提供しません(つまり、ほとんどのプロセッサーで)。現代PU(CPUおよびGPU))は、スケジューリングの指示に関しては非常に複雑です。アセンブリ(または疑似アセンブリ)の基本を知ることで、さらなる知識(キャッシュ)を提供するコンピュータアーキテクチャの本/コースを理解できるようになります。 、アウトオブオーダー実行、MMUなど)。通常、それらを理解するために複雑なISAを知る必要はありません(MIPS 5は非常に人気があります)ちゃんと覚えたら)。
なぜプロセッサを理解するのですか?何が起こっているのかをもっと理解してくれるかもしれません。素朴な方法で行列乗算を書いたとしましょう:
for i from 0 to N
for j from 0 to N
for k from 0 to N
A[i][j] += B[i][k] + C[k][j]
それはあなたの目的に「十分」であるかもしれません(それが4x4行列の場合はとにかくベクトル命令にコンパイルされるかもしれません)。しかし、大規模な配列をコンパイルする場合、非常に重要なプログラムがあります-それらを最適化する方法は? Assemblyでコードを記述した場合、数%の改善が見られる可能性があります(ほとんどの人がそうである場合を除いて、単純な方法で、レジスターを十分に活用せず、常にメモリにロード/保存し、その結果、プログラムがHL言語で遅くなります) 。
ただし、線を逆にして、魔法のようにパフォーマンスを上げることができます(なぜ?私は「宿題」のままにします)-大規模な行列のさまざまな要因に応じて、IIRCは10倍になることもあります。
for i from 0 to N
for k from 0 to N
for j from 0 to N
A[i][j] += B[i][k] + C[k][j]
とはいえ、それを実行できるコンパイラに取り組んでいます(gccの場合は グラファイト 、LLVMを使用する場合は Polly )。彼らはそれを次のように変換することもできます(申し訳ありません-私はメモリからブロックを書いています):
for i from 0 to N
for K from 0 to N/n
for J from 0 to N/n
for kk from 0 to n
for jj from 0 to n
k = K*n + kk
j = J*n + jj
A[i][j] += B[i][k] + C[k][j]
まとめると、アセンブリの基本を知ることで、プロセッサ設計からさまざまな「詳細」を掘り下げることができ、より高速なプログラムを作成できるようになります。 RISC/CISCまたはVLIW /ベクトルプロセッサ/ SIMD/...アーキテクチャの違いを知っておくとよいでしょう。ただし、x86は非常に複雑になる傾向があるため(おそらくARMも))、レジスターなどを知っていれば、開始するにはIMHOで十分です。
コンパイラの作成者でない場合、または高度に最適化されたもの(データ処理アルゴリズムなど)が必要な場合を除いて、アセンブリコーディングを学習してもメリットはありません。
Assemblyで記述されたコードの記述と保守は非常に難しいため、アセンブラー言語をよく理解している場合でも、他に方法がない限り、それを使用しないでください。
" SSEの最適化:ケーススタディ "の記事は、アセンブリに行った場合に何ができるかを示しています。著者は、アルゴリズムを100サイクル/ベクトルから17サイクル/ベクトルに最適化しました。