0

C++ ファイルを作成しましたが、それをアセンブリに出力したいと考えています。ただし、以下の例のようにアセンブリを最適化したい:

.386
.model flat, c

; Custom Build Step, including a listing file placed in intermediate directory
; but without Source Browser information
; debug:
; ml -c -Zi "-Fl$(IntDir)\$(InputName).lst" "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"
; release:
; ml -c "-Fl$(IntDir)\$(InputName).lst" "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"
; outputs:
; $(IntDir)\$(InputName).obj

; Custom Build Step, including a listing file placed in intermediate directory
; and Source Browser information also placed in intermediate directory
; debug:
; ml -c -Zi "-Fl$(IntDir)\$(InputName).lst" "-FR$(IntDir)\$(InputName).sbr" "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"
; release:
; ml -c "-Fl$(IntDir)\$(InputName).lst" "-FR$(IntDir)\$(InputName).sbr" "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"
; outputs:
; $(IntDir)\$(InputName).obj
; $(IntDir)\$(InputName).sbr

.code
_TEXT SEGMENT
_p$ = -8
_Array$ = 8
_size$ = 12
ClearUsingPointers PROC NEAR ; ClearUsingPointers, COMDAT
; Line 15
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 17
mov eax, DWORD PTR _Array$[ebp]
mov DWORD PTR _p$[ebp], eax
jmp SHORT $L280
$L281:
mov eax, DWORD PTR _p$[ebp]
add eax, 4
mov DWORD PTR _p$[ebp], eax
$L280:
mov eax, DWORD PTR _size$[ebp]
mov ecx, DWORD PTR _Array$[ebp]
lea edx, DWORD PTR [ecx+eax*4]
cmp DWORD PTR _p$[ebp], edx
jae SHORT $L278
; Line 18
mov eax, DWORD PTR _p$[ebp]
mov DWORD PTR [eax], 0
jmp SHORT $L281
$L278:
; Line 19
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
ClearUsingPointers ENDP ; ClearUsingPointers
_TEXT ENDS
END

上記のアセンブリはどのように生成されましたか。私が生成できるものはゴミでいっぱいです(他に説明する方法がわかりません)、手動で最適化し、コンパイルして実行できるようにするにはどうすれば短くできますか?ガベージでは、以下のような複数の行を参照しています。それらを削除できますか? :

PUBLIC  ?value@?$integral_constant@_N$0A@@tr1@std@@2_NB ; std::tr1::integral_constant<bool,0>::value
PUBLIC  ?value@?$integral_constant@_N$00@tr1@std@@2_NB  ; std::tr1::integral_constant<bool,1>::value
PUBLIC  ?value@?$integral_constant@I$0A@@tr1@std@@2IB   ; std::tr1::integral_constant<unsigned int,0>::value
PUBLIC  ?_Rank@?$_Arithmetic_traits@_N@std@@2HB     ; std::_Arithmetic_traits<bool>::_Rank
PUBLIC  ?_Rank@?$_Arithmetic_traits@D@std@@2HB      ; std::_Arithmetic_traits<char>::_Rank
PUBLIC  ?_Rank@?$_Arithmetic_traits@C@std@@2HB      ; std::_Arithmetic_traits<signed char>::_Rank
PUBLIC  ?_Rank@?$_Arithmetic_traits@E@std@@2HB      ; std::_Arithmetic_traits<unsigned char>::_Rank
;   COMDAT ?end@?$_Iosb@H@std@@2W4_Seekdir@12@B
CONST   SEGMENT
?end@?$_Iosb@H@std@@2W4_Seekdir@12@B DD 02H     ; std::_Iosb<int>::end
CONST   ENDS
;   COMDAT ?cur@?$_Iosb@H@std@@2W4_Seekdir@12@B
CONST   SEGMENT
?cur@?$_Iosb@H@std@@2W4_Seekdir@12@B DD 01H     ; std::_Iosb<int>::cur
CONST   ENDS
;   COMDAT ?beg@?$_Iosb@H@std@@2W4_Seekdir@12@B
CONST   SEGMENT
?beg@?$_Iosb@H@std@@2W4_Seekdir@12@B DD 00H     ; std::_Iosb<int>::beg
CONST   ENDS
;   COMDAT ?binary@?$_Iosb@H@std@@2W4_Openmode@12@B
CONST   SEGMENT
?binary@?$_Iosb@H@std@@2W4_Openmode@12@B DD 020H    ; std::_Iosb<int>::binary
CONST   ENDS
4

2 に答える 2

1

プロジェクトのプロパティで、C/C++ 設定、出力ファイル、アセンブリ出力を選択します。その出力は、選択した C/C++ 最適化設定によって異なります。

于 2012-12-12T03:20:04.753 に答える
0

スイッチを使用してコンパイルすることにより、Visual C++ から目的のアセンブリ出力を正確に取得できます/FA。これにより、指示のみを含むリストが出力されます。その他のオプションは次のとおりです。

  • /FAb命令を取得し、実際のサイズ (バイト単位) を示すコメントが続きます。
  • /FAcその命令をエンコードするために使用される実際のバイトが前にある命令を取得する
  • /FAs実際の C/C++ ソース コードから抽出されたコメントが点在する命令を取得し、アセンブリ コードのチャンクを生成した原因を示します。

CL のコマンドライン スイッチの標準構文に従って、これらのさまざまな組み合わせも使用できます。たとえば/FAcs、生のバイト、アセンブリ オペコード、およびソース コードからのコメント付きの抜粋を含むかなり複雑に見えるリストが生成されます。

これは、Keith Nicholas が述べたように、Visual Studio GUI 内のプロジェクト オプションの [C/C++ 設定] の下にある [アセンブリ出力] 設定でも制御できます。利用可能なオプションのほとんどはそこにありますが、bありません。使用する場合は、手動で指定する必要があります。(実際には文書化されていないオプションかもしれないと思いますが、これまでに見た MSVC のすべてのバージョンで動作します。)

単独の出力/FAは非常に無駄がありません。唯一のノイズは、アセンブリ命令の特定のチャンクを担当するソース コードの行を示すコメントです。これはまさに、質問の最初の例に示されているものです。これらが含まれないようにする方法があればいいのにと思いますが、見つかりません。関数の 2 つのバリアントの実装を簡単に比較することは非常に困難です。それらを手動で取り除くアプリがあります。

もちろん、これは最適化とは何の関係もないことに注意してください。/cコンパイラが生成する実際のバイナリ コード (つまり、リンクせずにコンパイルのみを行い、アセンブリ リストを生成するスイッチを渡していないと仮定します) は、使用するスイッチのバリエーションに関係なく同一です/FA。 . この追加情報は、何の効果もありません。これは、コードを分析する際に役立ちます。

あなたの本当の質問については、2番目のスニペットに示されている「ガベージ」を排除することについてです...これは、コンパイラーがオブジェクトファイルに順番に埋め込む必要がある一連のシンボルやその他のジャンクを定義する標準ライブラリヘッダーを含めたことに起因しますリンカーがその仕事をできるようにします。これが表示されないようにする方法はありません。次の 2 つのオプションしかありません。

  1. 標準ライブラリを実際に使用していない場合は、そのヘッダーを含めないでください。これにより、 を使用すると、より「きれいな」出力が得られます/FA

  2. 標準ライブラリを使用していて、コードをコンパイルするためにそれが必要な場合は、それを無視する必要があります。

「ガベージ」はファイルの先頭にのみあり、手動で簡単に削除できることに注意してください。生成されたオブジェクト コードを分析しようとしている場合、コンパイラが何をしているのかを理解するため、またはそれを出発点として使用して独自の最適化された実装を構築する場合、ファイルをテキスト エディターにロードし、検索するだけです。興味のある関数の名前を入力し、関連するコードに直接移動します。そこにはごみはありません。必要なコードのみ。

コンパイラで生成されたアセンブリ リストを取得し、コードを少し調整してから、アセンブラ (MASMなど)を介してシバン全体を実行することを目指している場合は、それを忘れてもかまいません。うまくいくという保証はありません。アセンブリ リストは、/FAアセンブラにフィードバックされるようには設計されていません。これらは情報提供のみを目的としています。それらから必要な情報を抽出し、コンパイラのバージョンをベースとして使用してアセンブリ コードを記述し、クリーンなソース ファイルをアセンブラにフィードします。

于 2016-10-03T13:58:25.940 に答える