タグ付けされた質問 「assembly」

アセンブリ言語(asm)プログラミングの質問。必ず、使用しているプロセッサや命令セット、およびアセンブラをタグ付けしてください。警告:.NETアセンブリの場合は、代わりにタグ[.net-assembly]を使用してください。Java ASMの場合は、代わりに[java-bytecode-asm]タグを使用してください。

1
Goがアセンブリをリンクしていません:未定義の外部関数
私は主に学習目的でいくつかのSIMDを書こうとしています。Goがアセンブリをリンクできることは知っていますが、正しく機能させることができません。 これが私が作ることができる最も最小限の例です(要素ごとのベクトル乗算): vec_amd64.s(注:実際のファイルには、RETエラーが発生するため、下に空白行があります) // func mul(v1, v2 Vec4) Vec4 TEXT .mul(SB),4,$0-48 MOVUPS v1+0(FP), X0 MOVUPS v2+16(FP), X1 MULPS X1, X0 // also tried ret+32 since I've seen some places do that MOVUPS X0, toReturn+32(FP) RET vec.go package simd type Vec4 [4]float32 func (v1 Vec4) Mul(v2 Vec4) Vec4 { return Vec4{v1[0] …
82 assembly  go 

4
インラインアセンブリコメントを追加すると、GCCで生成されたコードにこのような根本的な変更が生じるのはなぜですか?
だから、私はこのコードを持っていました: constexpr unsigned N = 1000; void f1(char* sum, char* a, char* b) { for(int i = 0; i < N; ++i) { sum[i] = a[i] + b[i]; } } void f2(char* sum, char* a, char* b) { char* end = sum + N; while(sum != end) { *sum++ = …

3
GCCパッドがNOPで機能するのはなぜですか?
私はしばらくの間Cを使用してきましたが、ごく最近、ASMを使い始めました。プログラムをコンパイルするとき: int main(void) { int a = 0; a += 1; return 0; } objdump逆アセンブリにはコードがありますが、retの後にnopsします。 ... 08048394 <main>: 8048394: 55 push %ebp 8048395: 89 e5 mov %esp,%ebp 8048397: 83 ec 10 sub $0x10,%esp 804839a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp) 80483a1: 83 45 fc 01 addl $0x1,-0x4(%ebp) …
81 c  gcc  assembly 

1
x86命令では、独自のエンコーディングとすべての引数が同時にメモリに存在する必要がありますか?
私は、RAMが単一の物理ページによってのみ裏付けられているLinux VMを実行できるかどうかを把握しようとしています。 これをシミュレートするために、KVMのネストされたページフォールトハンドラーを変更して、現在処理されているページフォールトに対応するものを除くすべてのネストされたページテーブル(NPT)エントリから現在のビットを削除しました。 Linuxゲストを起動しようとしたときに、次のようなメモリオペランドを使用するアセンブリ命令に気づきました。 add [rbp+0x820DDA], ebp 命令を含むページとオペランドで参照されるページ(この例では[rbp+0x820DDA])の現在のビットを復元するまで、ページフォールトループが発生します。 なぜそうなのかと思います。CPUはメモリページに順次アクセスするべきではありませんか。つまり、最初に命令を読み取ってから、メモリオペランドにアクセスしますか?または、x86では、命令ページとすべてのオペランドページに同時にアクセスできる必要がありますか? AMD Zen 1でテストしています。

1
なぜGCCは配列の初期化を集約して、最初にゼロ以外の要素を含めて全体をゼロで埋めるのですか?
なぜgccは残りの96個の整数だけではなく、配列全体をゼロで埋めるのですか?ゼロ以外の初期化子はすべて配列の先頭にあります。 void *sink; void bar() { int a[100]{1,2,3,4}; sink = a; // a escapes the function asm("":::"memory"); // and compiler memory barrier // forces the compiler to materialize a[] in memory instead of optimizing away } MinGW8.1とgcc9.2はどちらもこのようにasmを作成します(Godboltコンパイラエクスプローラー)。 # gcc9.2 -O3 -m32 -mno-sse bar(): push edi # save call-preserved EDI which …

1
GCCがstd :: vector :: sizeがこのループで変更されないと想定できないのはなぜですか?
if (i < input.size() - 1) print(0);このループで最適化されinput.size()、すべての反復で読み取られるわけではない同僚に私は主張しましたが、これはそうではありません! void print(int x) { std::cout << x << std::endl; } void print_list(const std::vector<int>& input) { int i = 0; for (size_t i = 0; i < input.size(); i++) { print(input[i]); if (i < input.size() - 1) print(0); } } gccオプション付きのコンパイラエクスプローラによると、-O3 -fno-exceptions実際にはinput.size()各反復を読み取りlea、減算を実行するために使用しています。 movq 0(%rbp), …
14 c++  gcc  assembly 

1
マシンコードの正確なコピーは、元の関数よりも50%遅く実行されます
組み込みシステムのRAMとフラッシュメモリからの実行を少し試しました。迅速なプロトタイピングとテストのために、私は現在Arduino Due(SAM3X8E ARM Cortex-M3)を使用しています。私が見る限り、Arduinoランタイムとブートローダーはここでは何の違いもないはずです。 ここに問題があります:ARM Thumb Assemblyで記述された関数(calc)があります。calcは数値を計算して返します。(> 1s runtime for the given input)次に、その関数のアセンブルされたマシンコードを手動で抽出し、それを生のバイトとして別の関数に入れました。両方の機能がフラッシュメモリに存在することが確認されています(アドレス0x80149および0x8017D、隣り合っています)。これは、逆アセンブルとランタイムチェックの両方で確認されています。 void setup() { Serial.begin(115200); timeFnc(calc); timeFnc(calc2); } void timeFnc(int (*functionPtr)(void)) { unsigned long time1 = micros(); int res = (*functionPtr)(); unsigned long time2 = micros(); Serial.print("Address: "); Serial.print((unsigned int)functionPtr); Serial.print(" Res: "); Serial.print(res); Serial.print(": "); Serial.print(time2-time1); Serial.println("us"); …

1
コンパイラが呼び出し先に保存されたレジスタの使用をここで主張するのはなぜですか?
次のCコードを考えてみます。 void foo(void); long bar(long x) { foo(); return x; } -O3またはのいずれかを使用してGCC 9.3でコンパイルすると-Os、次のようになります。 bar: push r12 mov r12, rdi call foo mov rax, r12 pop r12 ret clangからの出力は、呼び出し先保存レジスタとしてではrbxなく選択することを除いて同じですr12。 しかし、私はこのように見えるアセンブリを見たいと思っています/期待しています: bar: push rdi call foo pop rax ret 英語では、これが私の目に見えるものです。 呼び出し先が保存したレジスタの古い値をスタックにプッシュします x呼び出し先が保存したレジスタに移動します コール foo 移動しx、戻り値レジスタに呼び出し先保存レジスタから スタックをポップして、呼び出し先が保存したレジスタの古い値を復元します 呼び出し先に保存されたレジスターをいじる必要がないのはなぜですか?代わりにこれを行わないのはなぜですか?それはより短く、よりシンプルで、おそらくより高速に見えます: xスタックにプッシュ コール foo xスタックから戻り値レジスタにポップ 私の組み立ては間違っていますか?余分なレジスタをいじるよりも効率が悪いのでしょうか?これらの両方に対する答えが「いいえ」である場合、GCCまたはclangのいずれかがこのようにしないのはなぜですか? …
10 c  gcc  assembly  clang  x86-64 

1
.COMファイルをロードした後、DOSがSPレジスタを0xFFFEに設定するのはなぜですか?
.COMファイルに関するwikpediaページhttps://en.wikipedia.org/wiki/COM_fileには次のように記載されています。 DOSの.COMファイルは、すべてのx86セグメントレジスタを同じ値に設定し、SP(スタックポインタ)レジスタを0xFFFEに設定するため、スタックはメモリセグメントの最上部から始まり、そこから下に向かって動作します。 しかし、これは実際にはスタックをセグメントの先頭の1ワード下から開始するように設定します。スタックに値をプッシュすると、CPUはSPを0xFFFCにデクリメントしてそこに値を格納するため、セグメントのトップワードが無駄になります。DOSがSPを代わりに0に設定しない理由は何ですか?

2
最近のPCビデオハードウェアはHWでVGAテキストモードをサポートしていますか、それともBIOSがそれをエミュレートしますか(システム管理モードで)?
(0x31)などのバイトを物理線形アドレスのVGAテキスト(モード03)フレームバッファーに格納すると、16ビットのレガシーBIOS MBRモードで起動した最新のPCハードウェアで実際に何が起こりますか? そのリージョンのMTRRがUCに設定されているストアはどのくらい遅いですか? (Kaby Lake iGPUラップトップ1台での実験的テスト'1'B8000mov [es:di], eax、WC上のclflushoptがVGAメモリのUCとほぼ同じ速度であることを示しています。しかし、clflushopt movがないと、WCメモリへのストアはCPUを離れず、画面をまったく更新せず、超高速で実行されます。) すべてのストアのSMIではない場合、実際にリアルモードで再起動せずにパフォーマンスを実験するために、ユーザー空間のWBメモリのチャンクでこのコストを概算する方法はありますか?(たとえば、実際にはどこにも表示されないふりフレームバッファとしてBSSページを使用する)。 対応するフォントグリフは次の更新時に画面に表示されますが、ハードウェアスキャンアウトは実際にVRAM(またはiGPUの場合はDRAM)からASCII文字を読み取り、ビットマップフォントグリフに即座にマッピングしていますか?または、各ストアまたはvblankごとに1つのソフトウェアインターセプトがあるため、実際のハードウェアはビットマップフレームバッファーのみを処理する必要がありますか? レガシBIOSブートは、システム管理モード(SMM)を使用して USB kbd /マウスをPS / 2デバイスとしてエミュレートすることで知られています。VGAテキストモードのフレームバッファーにも使用されているのでしょうか。モード設定用のVGA I / Oポートに使用されていると思いますが、テキストフレームバッファがハードウェアでサポートされている可能性があります。ただし、ほとんどのコンピューターはすべての時間をグラフィックスモードで費やしているため、テキストモードのHWサポートを除外することは、ベンダーがしたいことのようです。(OTOH このブログは、自作のVerilog VGAコントローラーがテキストモードをかなり単純に実装できることを示唆しています。) 私は特にIntel SkylakeのiGPUを使用するシステムに興味がありますが、IntelおよびAMDの以前/後期のiGPU、および新旧のディスクリートGPUに興味があります。 (AMDとNVidia以外のベンダーを含みます。PCIeではなくPCIスロットを備えたSkylakeマザーボードがいくつかあります。最新のGPUファームウェアドライバーがテキストモードをエミュレートする場合、ハードウェアVGAテキストモードを備えた古いPCIビデオカードがいくつかあると考えられます。そしておそらくそのようなカードストアをSMIではなくPCIトランザクションにすることができます。) 私のデスクトップは、Asus Z170 Proゲーミングモボのi7-6700kです。アドオンカードはなく、DVI-D出力に1920x1200モニターを備えたiGPUのみです。@EldanがテストしているKaby Lake i5-7300HQシステムの詳細はわかりません。CPUモデルのみです。 私は2011年に uefiを使用してレガシービデオをエミュレートするフェニックスBIOSの特許US20120159520を見つけました。ビデオハードウェアベンダーにUEFI とネイティブの16ビットリアルモードオプションROMドライバーの両方の提供を要求する代わりに、SMMフックを介してベンダー提供のUEFIビデオドライバーを呼び出すリアルモードVGAドライバー(関数など)を提案します。int 10h 要約 [...]汎用ビデオオプションROMは、汎用ビデオSMMドライバーにビデオサービスの要求を通知します。このような通知は、ソフトウェアシステム管理割り込み(SMI)を使用して実行できます。通知されると、汎用ビデオSMMドライバーは、サードパーティのUEFIビデオドライバーにビデオサービスの要求を通知します。サードパーティのビデオドライバーは、要求されたビデオサービスをオペレーティングシステムに提供します。このようにして、サードパーティのUEFIグラフィックスドライバーは、UEFIディスプレイプロトコルをネイティブでサポートしていないオペレーティングシステムであっても、さまざまなオペレーティングシステムをサポートできます。 説明の多くは、int 10hすでに明らかにIVTを介してトラップするような呼び出しの処理をカバーしているため、意図的にSMIをトリガーするカスタムコードを簡単に実行できます。関連する部分は、ソフトウェアまたはハードウェアの割り込みをトリガーしないコードでも機能する必要があるテキストモードフレームバッファーへの直接保存について説明している部分です。(そのようなストアでSWをトリガーするHW以外、サポートされている場合は使用できると彼らは言っています。) テキストバッファのサポート 特定の実施形態では、アプリケーションは、VGAのテキストバッファを直接操作することができる。そのような実施形態では、汎用ビデオSMMドライバ130は、ハードウェアが740KB〜768KBメモリ領域(テキストバッファが配置されている)への読み取り/書き込みアクセス時にSMIトラッピングを提供するかどうかに応じて、2つの方法のうちの1つでこれをサポートする。 SMIトラッピングが利用可能な場合、ハードウェアは、各読み取りまたは書き込みアクセスでSMIを生成する。SMIトラップのトラップアドレスを使用して、正確なテキストの列と行を計算し、仮想テキスト画面の対応する行と列にアクセスできます。 代わりに、この領域では通常のメモリが有効になり、定期的なSMIを使用して、汎用ビデオSMMドライバー130はエミュレートされたハードウェアテキストバッファーの変更をスキャンし、ビデオドライバーによって維持される対応する仮想テキスト画面を更新します。どちらの場合も、変更が検出されると、文字が仮想テキスト画面に再描画されます。 これはBIOSベンダーの特許の1つに過ぎず、ほとんどのハードウェアが実際にどのように機能するか、または他のベンダーが異なることを行っているかどうかはわかりません。それは本質的にことを確認しないいくつかのハードウェアがいますが、その範囲内の店舗にどの缶トラップが存在します。(それが彼らが彼らの特許でカバーすることを決めた仮説的な可能性でない限り) 私が念頭に置いているユースケースでは、画面の更新時にのみトラップする方が、すべてのストアでトラップするよりもはるかに高速なので、どのハードウェア/ファームウェアがどのように機能するか知りたいです。 この質問の動機 第7世代Intel CoreのビデオRAMでインクリメントするASCII 10進カウンターを最適化-ASCIIテキストカウンターの新しい数字をビデオRAMの同じ数バイトに繰り返し保存します。 Linuxの32ビットユーザー空間のコードのバージョンをWBメモリでテストしました。movnti各ストアの後にCPUがWCバッファーをビデオRAMに同期するさまざまな方法(および場合によってはときどき)タイマー割り込み)。ただし、リアルモードブートローダーの状況がDRAMへの格納だけでなく、SMIをトリガーする場合、これは現実的ではありません。 WBメモリでは、movntiaを使用したスト​​アのフラッシュは、を使用したフラッシュlock …

2
L2 HWプリフェッチャーは本当に役に立ちますか?
私はWhisky Lake i7-8565Uで、512 KiBのデータ(L2キャッシュサイズの2倍)をコピーするためのパフォーマンスカウンターと時間を分析しており、L2 HWプリフェッチャーの作業に関して誤解に直面しています。 でインテル・マニュアル第4巻MSR MSRがある0x1A4ビット0(無効にする1)L2 HWプリフェッチャをcontrolloingするためのものであるの。 次のベンチマークを検討してください。 memcopy.h: void *avx_memcpy_forward_lsls(void *restrict, const void *restrict, size_t); memcopy.S: avx_memcpy_forward_lsls: shr rdx, 0x3 xor rcx, rcx avx_memcpy_forward_loop_lsls: vmovdqa ymm0, [rsi + 8*rcx] vmovdqa [rdi + rcx*8], ymm0 vmovdqa ymm1, [rsi + 8*rcx + 0x20] vmovdqa [rdi + rcx*8 + 0x20], ymm1 …


2
Cortex-A72で-O3ではなく-O0を使用した単純なタイトループのサイクルでこの高い変動が発生する原因は何ですか?
コードの一部に対して非常に一貫性のあるランタイムを取得するためにいくつかの実験を行っています。私が現在計時しているコードは、かなり恣意的なCPUバウンドのワークロードです。 int cpu_workload_external_O3(){ int x = 0; for(int ind = 0; ind < 12349560; ind++){ x = ((x ^ 0x123) + x * 3) % 123456; } return x; } 割り込みを無効にし、上記の関数の10回の試行を実行するカーネルモジュールを作成しました。各試行のタイミングは、前後のクロックサイクルカウンターの差をとることによって計っています。その他の注意事項: マシンはARM Cortex-A72であり、それぞれ4コアの4ソケット(それぞれに独自のL1キャッシュがある) クロック周波数スケーリングはオフです ハイパースレッディングはサポートされていません マシンは、一部の最低限のシステムプロセスを除いて、実質的に何も実行していません 言い換えると、システム変動のほとんど/すべての原因が説明されていると私は信じています。特に、割り込みを無効にしてカーネルモジュールとして実行した場合spin_lock_irqsave()、コードは実行間でほぼ同じパフォーマンスを達成するはずです(たぶん小さなパフォーマンスヒット)最初の実行では、いくつかの命令が最初にキャッシュにプルされますが、それだけです)。 実際、ベンチマークされたコードがでコンパイルされた場合、-O3平均で〜135,845,192のうち最大で200サイクルの範囲があり、ほとんどの試行でまったく同じ時間がかかりました。ただし、を使用してコンパイルする-O0と、範囲は262,710,916のうち158,386サイクルまで増加します。範囲とは、最長実行時間と最短実行時間の差を意味します。さらに、-O0コードでは、どの試行が最も遅い/最も速いかについて一貫性があまりありません-直感的には、ある場合には、最も速いものが最初であり、最も遅いものが直後のものでした! それで、-O0コードの変動性のこの高い上限を引き起こしている可能性があるものは何ですか?アセンブリを見ると、-O3コードはすべて(?)をレジスタに格納しているようですが、-O0コードにはたくさんの参照spがあるため、メモリにアクセスしているようです。しかし、それでも、すべてがL1キャッシュに取り込まれ、かなり確定的なアクセス時間でそこに座っていることが期待されます。 コード ベンチマーク対象のコードは上記のスニペットにあります。組み立ては下にあります。とgcc 7.4.0以外はフラグなしでコンパイルされました。-O0-O3 -O0 0000000000000000 <cpu_workload_external_O0>: 0: d10043ff sub sp, sp, …

1
sqrtsd命令のレイテンシが入力に基づいて変化するのはなぜですか?Intelプロセッサ
まあ上でインテル固有のガイドには、「sqrtsd」と呼ばれる命令は18サイクルのレイテンシーを持っていることが述べられています。 私はそれを自分のプログラムでテストしました。たとえば、0.15を入力として受け取った場合は正しいです。しかし、256(または任意の2 ^ x)の数をとると、レイテンシはわずか13になります。なぜですか? 私が持っていた1つの理論は、13は「sqrtss」のレイテンシであり、「sqrtsd」と同じですが32ビット浮動小数点で行われるため、プロセッサは256ビットが32ビットに適合し、そのバージョンを使用することを理解するのに十分スマートであるということです一方、0.15は有限の方法で表現できないため、完全な64ビットが必要です。 私はインラインアセンブリを使用してそれをやっています、これはgcc -O3と-fno-tree-vectorizeでコンパイルされた関連部分です。 static double sqrtsd (double x) { double r; __asm__ ("sqrtsd %1, %0" : "=x" (r) : "x" (x)); return r; }

2
分解されたバイナリ爆弾フェーズ3のロジックを理解する難しさ
バイナリ爆弾ラボから次のアセンブリプログラムがあります。目的は、explode_bomb関数をトリガーせずにバイナリを実行するために必要なキーワードを決定することです。このプログラムのアセンブリの分析についてコメントしましたが、すべてを一緒に結合するのに問題があります。 必要な情報はすべて揃っていると思いますが、それでも実際の根本的なロジックを確認できず、行き詰まっています。どんな助けにも感謝します! 以下は、逆アセンブルされたプログラム自体です。 0x08048c3c <+0>: push %edi 0x08048c3d <+1>: push %esi 0x08048c3e <+2>: sub $0x14,%esp 0x08048c41 <+5>: movl $0x804a388,(%esp) 0x08048c48 <+12>: call 0x80490ab <string_length> 0x08048c4d <+17>: add $0x1,%eax 0x08048c50 <+20>: mov %eax,(%esp) 0x08048c53 <+23>: call 0x8048800 <malloc@plt> 0x08048c58 <+28>: mov $0x804a388,%esi 0x08048c5d <+33>: mov $0x13,%ecx 0x08048c62 <+38>: mov %eax,%edi 0x08048c64 …

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.