私は約10年間、高レベルの言語(Python、C#、VBA、VB.NET)でプログラミングを行ってきましたが、「裏側」で何が起こっているのか全く理解していません。
アセンブリを学習することの利点は何ですか?また、プログラマーとしてどのように役立つでしょうか?より高いレベルのコードで記述したものとアセンブリで行われることとの正確な関係を示すリソースを提供していただけますか?
for
ループの外側で変数を宣言することにより、ループを最適化していると考えることを避けることができます。例
私は約10年間、高レベルの言語(Python、C#、VBA、VB.NET)でプログラミングを行ってきましたが、「裏側」で何が起こっているのか全く理解していません。
アセンブリを学習することの利点は何ですか?また、プログラマーとしてどのように役立つでしょうか?より高いレベルのコードで記述したものとアセンブリで行われることとの正確な関係を示すリソースを提供していただけますか?
for
ループの外側で変数を宣言することにより、ループを最適化していると考えることを避けることができます。例
回答:
あなたはそれが本当にどのように機能するかを理解するからです。
要するに、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
so.c
(私が持っているようにstackoverflowの質問のためのファイルをso.py
、so.awk
など)すぐに物事をテストします。So.S .. :)
gcc -O -c -g -Wa,-ahl=so.s so.c
、Cコードの各行のアセンブリ出力を確認できます。これにより、何が起こっているのかが少しわかりやすくなります。
5:so.c
5行目のコードを検索して見つけることができますso.c
。
あなたが求める答えはここにあると思います:http : //www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language
記事からの引用:
確かに、アセンブリで次の顧客のアプリを作成することはないでしょう。アセンブリを学習することで得られることはまだたくさんあります。現在、アセンブリ言語は、主に直接ハードウェア操作、特殊なプロセッサ命令へのアクセス、または重大なパフォーマンスの問題に対処するために使用されています。典型的な用途は、デバイスドライバー、低レベルの組み込みシステム、およびリアルタイムシステムです。
問題の事実は、高レベルの言語が複雑になるほど、また記述されるADT(抽象データ型)が増えるほど、これらのオプションをサポートするためのオーバーヘッドが大きくなることです。.NETのインスタンスでは、おそらくMSILが肥大化しています。MSILを知っていたら想像してみてください。これは、アセンブリ言語が輝くところです。
アセンブリ言語はプログラマーと同じくらいプロセッサに近いため、適切に設計されたアルゴリズムが非常に優れています。アセンブリは速度の最適化に最適です。パフォーマンスと効率がすべてです。アセンブリ言語により、システムのリソースを完全に制御できます。アセンブリラインと同様に、単一の値をレジスタにプッシュし、メモリアドレスを直接処理して値またはポインターを取得するコードを記述します。
アセンブリを記述するとは、プロセッサとメモリがどのように連携して「物事を実現する」かを正確に理解することです。アセンブリ言語は不可解であり、アプリケーションのソースコードサイズは高レベル言語のサイズよりもはるかに大きいことに注意してください。しかし、それを間違えないでください。アセンブリをマスターするための時間と労力を費やすことをいとわない場合、あなたは良くなり、フィールドで目立つようになります。
さらに、この本は、コンピューターアーキテクチャの簡易バージョンを持っているため、この本をお勧めします。イリノイ大学アーバナ校/シャンペーン校
私の謙虚な意見では、それはあまり役に立ちません。
私はx86アセンブリをよく知っていました。アセンブリが私のコースで出てきたとき、それは少し助けになり、インタビュー中に一度現れ、コンパイラ(Metrowerks)が悪いコードを生成していることを証明するのに役立ちました。コンピューターが実際にどのように機能するかは魅力的で、私はそれを学んだことで知的に豊かに感じています。当時はとても楽しかったです。
ただし、今日のコンパイラは、ほとんどすべてのコードで誰よりもアセンブリを生成するのに優れています。あなたがコンパイラを書いているか、コンパイラが正しいことをしていることを確認していない限り、おそらくそれを学ぶことによって時間を浪費しているでしょう。
私は、C ++プログラマーが今でも有用に尋ねる多くの質問が、アセンブリを知ることによって知らされることを認めます。たとえば、スタック変数またはヒープ変数を使用する必要がありますか?値またはconst参照で渡す必要がありますか?ただし、ほとんどすべての場合、これらの選択は計算時間の節約よりもコードの可読性に基づいて行う必要があると思います。(たとえば、変数をスコープに制限する場合は常にスタック変数を使用します。)
私の謙虚な提案は、本当に重要なスキルに焦点を当てることです:ソフトウェア設計、アルゴリズム分析、問題解決。大きなプロジェクトを開発した経験があれば、直観力が向上し、アセンブリを知ることよりも価値が高まります(私の意見では)。
作業しているシステムの1つのレベル「深い」に精通している必要があります。一度に行き過ぎをスキップすることは悪いことではありませんが、望むほど役立つものではないかもしれません。
高水準言語のプログラマーは、低水準言語を習得する必要があります(Cは優れたオプションです)。コンピューターにオブジェクトのインスタンス化、ハッシュテーブル、またはセットの作成を指示するときに、裏側で何が行われているのかを理解するためにアセンブリに至る必要はありませんが、コーディングできる必要があります。それら。
Javaプログラマーにとって、Cを学ぶことは、引数を渡すメモリ管理に役立ちます。Cで大規模なJavaライブラリを作成すると、Setの実装をいつ使用するかを理解するのに役立ちます(ハッシュが必要ですか?ツリーが必要ですか?)。スレッド環境でchar *を処理すると、Stringが不変である理由を理解するのに役立ちます。
次のレベルに進む... ACプログラマーはアセンブリにある程度精通している必要があり、アセンブリの種類(組み込みシステムショップでよく見られます)は、ゲートのレベルで物事を理解するのに役立つでしょう。ゲートを操作する人は、量子物理学を知っている必要があります。そして、それらの量子物理学者は、次の抽象化が何であるかをまだ解明しようとしています。
あなたが知っている言語のリストでCやC ++について言及しなかったので。アセンブリについて考える前に、よく学ぶことを強くお勧めします。CまたはC ++は、マネージ言語で完全に透過的なすべての基本概念を提供します。このページで言及されている概念のほとんどは、実際のプロジェクトで使用できる最も重要な言語の1つで理解できます。それはあなたのプログラミングスキルへの真の付加価値です。アセンブリは非常に特定の領域で使用され、CやC ++ほど有用ではないことに注意してください。
さらに、アンマネージ言語がどのように機能するかを理解する前に、アセンブリに飛び込むべきではないと言うこともできます。それはほとんど必須の読書です。
さらに下に行く場合は、アセンブリを学習する必要があります。言語の各構成要素がどのように作成されているかを正確に知りたい。有益ですが、レベルの複雑さはまったく異なります。
言語を熟知している場合は、少なくとも1レベル低い抽象化技術の基本的な知識が必要です。
どうして?物事がうまくいかない場合、基礎となるメカニズムの知識により、奇妙な問題のデバッグがはるかに簡単になり、より効率的なコードを自然に書くことができます
Python(/ CPython)を例として使用すると、奇妙なクラッシュやパフォーマンスの低下が発生し始めた場合、Cコードをデバッグする方法の知識は非常に役立ちます。参照カウントのメモリ管理方法の知識と同じです。これは、C拡張機能として何かを書くタイミング/場合などを知るのにも役立ちます...
この場合の質問に答えるために、アセンブリの知識は経験豊富なPython開発者には実際には役に立たないでしょう(抽象化の手順が多すぎます-Pythonで行われたものは多くのアセンブリ命令になります)
..しかし、Cの経験がある場合は、「次のレベル」(アセンブリ)を知っていると本当に役立ちます。
同様に、CoffeScriptを使用している場合、Javascriptを知ることは(非常に)役立ちます。Clojureを使用している場合は、Java / JVMの知識が役立ちます。
このアイデアは、プログラミング言語以外でも機能します。アセンブリを使用している場合は、基礎となるハードウェアの機能に精通することをお勧めします。あなたがウェブデザイナーであるなら、ウェブアプリケーションがどのように実装されているかを知ることは良い考えです。あなたが自動車整備士である場合、いくつかの物理学の知識を持っていることをお勧めします
小さなcプログラムを作成し、出力を逆アセンブルします。それで全部です。ただし、オペレーティングシステムの利益のために追加される「ハウスキーピング」コードの程度に応じて準備してください。
アセンブリは、メモリ、プロセッサレジスタなどを直接処理するため、内部で何が起こっているのかを理解するのに役立ちます。
オペレーティングシステムの複雑さをすべて複雑にすることなくベアメタルにしたい場合は、アセンブリ言語でArduinoをプログラミングしてみてください。
プログラマーはすべてのタイプではないので、決定的な答えはありません。何が潜んでいるのか知る必要がありますか?もしそうなら、それを学ぶ。単に好奇心からそれを学びたいだけですか?もしそうなら、それを学ぶ。それがあなたに実際的な利益をもたらさないのであれば、なぜ気にするのですか 車を運転するために、整備士の知識が必要ですか?メカニックは、車で作業するために、エンジニアのレベルの知識が必要ですか?これは深刻な例えです。整備士は、彼が維持する車両を深く理解するために潜ることなく、非常に優れた生産的な整備士になることができます。音楽についても同じです。メロディー、ハーモニー、リズムの複雑さを本当に歌い手や演奏者にしようと思いますか?いいえ。非常に才能のあるミュージシャンの中には、ドリアンとリディアンのモードの違いを言うまでもなく、楽譜をなめることができない人もいます。あなたがしたい場合は、罰金が、いいえ、あなたはする必要はありません。あなたがWeb開発者であれば、アセンブリには私が考えることができる実用的な用途はありません。あなたが組み込みシステムまたは本当に特別な何かにいるなら、それは必要かもしれませんが、もしそうなら、あなたはそれを知っているでしょう。
以下は、非高水準言語を学習することのこれらの価値に関するJoelの見解です。http: //www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html
実際、おそらくあなたに最適なのは、(私の知る限り)どこにも存在しないクラスです:マシン/アセンブラー言語とストレージアドレッシングの概念の簡単な概要とコンパイラー構築のツアーを組み合わせたクラスです、コード生成、およびランタイム環境。
問題は、C#やPythonなどのハードウェアから遠く離れた高レベル言語では、実行するすべての動きが数千ではなくても数百の機械語命令に変わるという事実を本当に理解していないということです。高レベル言語の数行が膨大な量のストレージにアクセスして変更する原因になることを理解する傾向はありません。「カバーの下」で何が起こっているのかを正確に知る必要はありませんが、何が起こっているのか、発生している種類の一般的な概念を理解する必要があります。
この質問に対する私の答えは比較的最近進化しました。既存の回答は、私が過去に言ったことをカバーしています。実際、これは依然として上位の回答 -「高レベルプログラミングでの構成体の評価」でカバーされていますが、言及する価値があると思う特別なケースです...
調査を参照しているこのJeff Atwoodのブログ投稿によると、割り当てを理解することはプログラミングを理解する上で重要な問題です。学習者のプログラマーは、表記法がコンピューターがたどるステップを表していることを理解し、そのステップの理由を理解するか、数学方程式などの誤解を招く類推によって絶えず混乱します。
まあ、6502アセンブラーから次を理解したら...
LDA variable
CLC
ADC #1
STA variable
それは本当に単なる手順です。次に、それを割り当てステートメントに変換することを学ぶと...
variable = variable + 1;
数学的な方程式の誤解を招くようなアナロジーは必要ありません-マッピングするための正しいメンタルモデルが既にあります。
編集 -もちろん、あなたが得る説明LDA variable
が基本的にACCUMULATOR = variable
である場合、これはいくつかのチュートリアルと参考文献から得られるものであり、あなたが始めたところに戻ってしまい、何の助けにもなりません。
私は第二言語として6502アセンブラーを学びました。最初はコモドール・ベーシックで、当時あまり学んだことはありませんでした。それは、学ぶべきことがほとんどなかったからです。 。私は14歳のオタクだったからです。
私がやったことを行うことはお勧めしませんが、非常に単純なアセンブラー言語でいくつかの非常に単純な例を研究することは、高水準言語を学ぶ前に価値のある予備になるかもしれないと思います。
コンパイラの作成者である場合、または高度に最適化されたもの(データ処理アルゴリズムなど)が必要な場合を除き、アセンブリコーディングを学習してもメリットはありません。
アセンブリで記述されたコードの記述と保守は非常に難しいため、他の方法がない限り、アセンブラー言語を熟知していても使用しないでください。
「SSEの最適化:ケーススタディ」の記事は、アセンブリに行く場合に何ができるかを示しています。著者は、アルゴリズムを100サイクル/ベクトルから17サイクル/ベクトルに最適化することに成功しました。
アセンブリでの書き込みは、詳細の量(レジスタの割り当てなど)によって魔法の速度を上げることはありません。おそらく最も些細なアルゴリズムを書くでしょう。
さらに、最新の(読み取り-70〜80年代以降に設計された)プロセッサアセンブリでは、何が起こっているか(つまり、ほとんどのプロセッサ)を知るのに十分な数の詳細が得られません。最新のPU(CPUおよびGPU)は、スケジューリングの指示に関しては非常に複雑です。アセンブリ(または疑似アセンブリ)の基本を知ることで、コンピュータアーキテクチャの書籍/コースを理解でき、さらに知識(キャッシュ、アウトオブオーダー実行、MMUなど)が得られます。通常、複雑なISAを理解してそれらを理解する必要はありません(MIPS 5は非常に人気のあるIIRCです)。
プロセッサを理解する理由 何が起こっているのかをもっと理解できるかもしれません。素朴な方法で行列乗算を書くとしましょう:
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マトリックスの場合は、とにかくベクトル命令にコンパイルされるかもしれません)。しかし、大規模な配列をコンパイルする際に非常に重要なプログラムがあります-それらを最適化する方法は?アセンブリでコードを書くと、数%の改善が得られるかもしれません(ほとんどの人がそうするようにしない限り-単純な方法で、レジスタを十分に活用せず、常にメモリにロード/保存し、実際にはHL言語よりも遅いプログラムを使用します) 。
ただし、thoの行を逆にして魔法のようにパフォーマンスを向上させることができます(なぜですか?「宿題」のままにします)。
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 / vector processor / SIMD / ...アーキテクチャの違いを知っておくとよいでしょう。ただし、x86は非常に複雑になる傾向があるため(おそらくARMでも)、x86から始めません。レジスターなどを知ることは、開始するには十分です。
要するに、アセンブリーを学べばもっとできることがあるからだと思う。アセンブリを学習すると、組み込みデバイスプログラミング、セキュリティの浸透と回避、リバースエンジニアリング、およびシステムプログラミングの領域へのアクセスが許可されます。これらは、アセンブラーがわからない場合は作業が非常に困難です。
プログラムのパフォーマンスを改善するために学習することに関して、これはアプリケーションのプログラミングでは疑わしいです。ほとんどの場合、ディスクとネットワークの両方でのI / Oアクセスの最適化、GUIの構築方法の最適化、適切なアルゴリズムの選択、すべてのコアの最大化など、このレベルの最適化に達する前に最初に集中することが非常に多くあります、最高のハードウェアマネーで実行すると、購入してインタープリター言語からコンパイル言語に切り替えることができます。他のエンドユーザー向けのソフトウェアを作成する場合を除き、ハードウェアはプログラマの1時間あたりの賃金と比較して、特にクラウドの可用性に比べて安価です。
また、最後のバージョンを書いてから1年後に、バスにぶつかったり、コードベースに戻ったり、コードベースに戻って変更した後、コードの可読性とプログラム実行速度の向上を比較検討する必要があります。
アルゴリズムの学習をお勧めします:並べ替え、リンクリスト、バイナリツリー、ハッシュなど。
また、コンピュータプログラムの構造と解釈を参照してください。また、このビデオコースでは、アルゴリズム(いくつかのプリミティブコマンド、1つのLispプリミティブ、およびいくつかのアセンブラーの挑発的)。
最後に、アセンブラーを学習する必要がある場合は、ARMのような簡単なものを学習します(x86の約4倍のデバイスで使用されます)。
答えは、単に使用している言語を最後に解釈またはアセンブラーにコンパイルする必要があるからです。言語や機械に関係なく。
言語の設計は、CPUの動作方法から派生しています。低レベルのプログラムではより多く、高レベルのプログラムではより少ない。
最後に、小さなアセンブラーだけでなく、CPUアーキテクチャーを知っておく必要があるというだけでなく、アセンブラーを学習することで学習することもできます。
いくつかの例:これがなぜ機能しないのかを理解していないJavaプログラマーが多くおり、それを実行したときに何が起こるかさえ知らない。
String a = "X";
String b = "X";
if(a==b)
return true;
少しのアセンブラを知っていれば、それは、メモリロケーションの内容と、そのロケーションを「指す」ポインタ変数の数が同じではないことを常に知っているでしょう。
さらに悪いことに、出版された本でさえ、Javaプリミティブが値によって渡され、オブジェクトが参照によって渡されるようなものを読むことになりますが、これは完全に間違っています。Javaのすべての引数は値で渡され、Javaはオブジェクトを関数に渡すことはできません。値のみで渡されるポインターのみを渡します。
今、アセンブラーで何が起こっているのか明らかな場合、そうでない場合、ほとんどの著者があなたにうそをついていると説明するのは非常に複雑です。
もちろん、これらの影響は微妙ですが、後で実際のトラブルに巻き込まれる可能性があります。アセンブラを知っている場合、それは問題ではありません。そうでない場合、デバッグの長い夜になります。
String a = "X"; String b = "X"; if( a==b) return true;
され、実際にはありません== true
ので、と呼ばれるもののString interning
コンパイラがないこと。他のすべてのJavaステートメントも間違っています。Javaにはポインターはなく、同じものではない参照があります。そして、そのいずれもアセンブラーとは何の関係もありません。Javaは、プリミティブを値で渡し、参照を値で渡します。Javaにはポインターがないため、何も渡すことができません。繰り返しますが、ASMの知識とは無関係です。