Visual C ++를 사용하여 코드 뒤의 어셈블리를 보는 방법은 무엇입니까?


117

나는 두 줄의 코드의 효율성에 관한 또 다른 질문을 읽고 있었고 OP는 그가 코드 뒤의 어셈블리를 보았고 두 줄이 어셈블리에서 동일하다고 말했습니다. 여담을 제외하고, 프로그램이 컴파일 될 때 생성 된 어셈블리 코드를 어떻게 볼 수 있습니까?

Microsoft의 Visual C ++를 사용하고 있지만 Visual Basic으로 작성된 코드 뒤에있는 어셈블리를 볼 수 있는지도 알고 싶습니다.

그렇다면 C ++ 및 Visual Basic과 같은 고급 언어로 작성된 프로그램 뒤에있는 어셈블리 코드를 어떻게 볼 수 있습니까?


다른 사람들이 이미 언급했듯이 msvc의 어셈블리 목록이라고합니다. 지루한 단계를 자동화하기 위해 편집기 컨텍스트 메뉴에 항목을 추가하는 간단한 플러그인을 만들었습니다. marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

답변:


149

몇 가지 접근 방식이 있습니다.

  1. Visual Studio (및 Eclipse도)에서 C ++를 디버깅하는 동안 일반적으로 어셈블리 코드를 볼 수 있습니다. 이를 위해 Visual Studio에서 문제의 코드에 중단 점을 설정하고 디버거가이를 때리면 클릭하고 "어셈블리로 이동"을 찾습니다 (또는 CTRL + ALT + D를 누릅니다).

  2. 두 번째 방법은 컴파일하는 동안 어셈블리 목록을 생성하는 것입니다. 이를 위해 프로젝트 설정-> C / C ++-> 출력 파일-> ASM 목록 위치로 이동하여 파일 이름을 입력합니다. 또한 "Assembly Output"을 "Assembly With Source Code"로 선택합니다.

  3. 프로그램을 컴파일하고 타사 디버거를 사용하십시오. 이를 위해 OllyDbg 또는 WinDbg를 사용할 수 있습니다. 또한 IDA (대화 형 디스어셈블러)를 사용할 수 있습니다. 그러나 이것은 그것을하는 하드 코어 방법입니다.


5
전체 프로그램 최적화가 활성화 된 정적 라이브러리를 컴파일 할 때는 접근 방식 # 2가 작동하지 않습니다 (적어도 VS2010에서는). 의미가 있습니다-컴파일러가 아직 최종 코드를 생성하지 않았습니다.
dhaffey 2013 년

3
Visual Studio 2017에서 "Goto Disassembly"라고합니다
Matthias

접근 방식 # 2를 사용하여 어셈블리를 어떻게 볼 수 있습니까?
user1507435

기본 위치를 사용한 경우 디버그 디렉토리에 .asm 파일이 표시되어야합니다.
user3015682

28

추가 참고 사항 : 디버그 어셈블러 출력과 릴리스 1 사이에는 큰 차이가 있습니다. 첫 번째는 컴파일러가 C ++에서 어셈블러 코드를 생성하는 방법을 배우는 데 좋습니다. 두 번째는 컴파일러가 다양한 C ++ 구문을 최적화하는 방법을 배우는 데 좋습니다. 이 경우 일부 C ++에서 asm으로의 변환이 명확하지 않습니다.


디버그 실행 파일을 분해 할 때 실행중인 코드의 압축이 풀리는 것처럼 보이지만 릴리스 버전에서는 발생하지 않습니다. 또한 PEiD로 둘 다 열 때 디버그 버전 만 "Microsoft Visual C ++ 8.0 [Debug]"로 표시됩니다.
jyz

9
이것은 절대적으로 사실입니다. 그러나 그것은 질문에 전혀 대답하지 않습니다.
imallett

25

cl 컴파일러에 대해 / FA 스위치를 지정합니다. 스위치의 값에 따라 어셈블리 코드 또는 고급 코드 및 어셈블리 코드 만 통합됩니다. 파일 이름은 .asm 파일 확장자를 갖습니다. 지원되는 값은 다음과 같습니다.


  • / FA 어셈블리 코드; .asm
  • / FAc 기계 및 조립 코드; .대구
  • / FAs 소스 및 어셈블리 코드; .asm
  • / FAcs 기계, 소스 및 어셈블리 코드; .대구

10

가장 쉬운 방법은 디버거를 실행하고 디스 어셈블리 창을 확인하는 것 입니다.


8

이 답변의 이전 버전 (rextester.com의 "해킹")은 http://gcc.godbolt.org/ 에서 ARM, x86 및 x86-64 용 CL 19 RC 를 제공 하므로 대부분 중복됩니다 (Windows 호출 규칙을 대상으로 함). , 해당 사이트의 gcc, clang 및 icc와 달리).

Godbolt 컴파일러 탐색기는 컴파일러 asm 출력을 멋지게 형식화하고 지시문의 "노이즈"를 제거하도록 설계되었으므로 인수를 취하고 값을 반환하는 간단한 함수에 대해 asm을 살펴볼 때 사용하는 것이 좋습니다 (그러므로 최적화).

잠시 동안 CL은 http://gcc.beta.godbolt.org/ 에서 사용할 수 있었지만 메인 사이트는 아니었지만 지금은 둘 다에 있습니다.


http://rextester.com/l/cpp_online_compiler_visual 온라인 컴파일러 에서 MSVC asm 출력을 얻으려면 : /FAs명령 줄 옵션에 추가 합니다. 프로그램이 자체 경로를 찾고 경로를 찾아서 .asm덤프하도록하십시오. 또는 .exe.

예 : http://rextester.com/OKI40941

#include <string>
#include <boost/filesystem.hpp>
#include <Windows.h>

using namespace std;

static string my_exe(void){
    char buf[MAX_PATH];
    DWORD tmp = GetModuleFileNameA( NULL, // self
                                  buf, MAX_PATH);
    return buf;
}

int main() {
    string dircmd = "dir ";
    boost::filesystem::path p( my_exe() );
    //boost::filesystem::path dir = p.parent_path();

    // transform c:\foo\bar\1234\a.exe 
    // into      c:\foo\bar\1234\1234.asm
    p.remove_filename();
    system ( (dircmd + p.string()).c_str() );

    auto subdir = p.end();      // pointing at one-past the end
    subdir--;                   // pointing at the last directory name
    p /= *subdir;               // append the last dir name as a filename
    p.replace_extension(".asm");
    system ( (string("type ") + p.string()).c_str() );
//    std::cout << "Hello, world!\n";
}

... code of functions you want to see the asm for goes here ...

type의 DOS 버전입니다 cat. asm을보고 싶은 함수를 찾기 어렵게 만드는 더 많은 코드를 포함하고 싶지 않았습니다. (그 목표에 표준 : : 문자열과 부스트 런 카운터를 사용하지만!이 처리 (그리고있어 문자열에 대한 자세한 가정을 일부 C 스타일의 문자열 조작의 결과에) 큰 버퍼를 사용하여 최대 길이 안전 / 할당을 무시 GetModuleFileNameA겠습니까 전체 기계 코드가 훨씬 적습니다.)

IDK cout << p.string() << endl는 그 길이를 인쇄하는 것이 단순한 이름이 아니라는 것을 보여도 기본 이름 (즉, 디렉토리없이 파일 이름) 만 표시합니다. (Ubuntu 15.10의 Chromium48). 에서 cout또는 프로그램의 표준 출력과 웹 브라우저 사이 에 백 슬래시 이스케이프 처리가있을 수 있습니다 .


@MichaelPetch : 아, 돌아 가면서 그 밖 입니다 제가 시도했던 것. .c_str()포인터처럼 보이는 것을 인쇄합니다. 링크를 따라 가면 hexdump a std::string(사용 안함 #if 0)에 대한 코드가 표시 됩니다. 문자열은 괜찮지 만 cout웹 브라우저에 전달되지 않습니다. 비 ASCII 문자도없고 백 슬래시 만 있습니다.
Peter Cordes 2016

뭔가 빠졌을 수도 있지만 p 를 파일 이름으로 subdir--; p /= *subdir;줄이지 않았 습니까? 아니면 인쇄하려는 내용을 오해하고있을 수도 있습니다.
Michael Petch

나는 꽤 이해하지 못하는 것 같아요 subdir--다음에 p /= *subdirsubdir원래이었다p.end()
마이클 페치

@MichaelPetch : 업데이트 된 댓글. 파일 이름으로 사용할 경로의 마지막 디렉터리 구성 요소를 가져와야했습니다. 효과는 있지만 GetModuleFileNameA돌아 온다고 생각했기 때문에 운동하는 데 오랜 시간이 걸렸습니다 a.exe. 내가 그것을 헥스 덤핑하고 그것이 작동하고 있다는 것을 알고있는 길이를 인쇄하기 전까지는 아니었다. 그리고 나는 프로그램이 경로를 조작하게 할 수 있었다. 나는 단지 경로를 인쇄 할 수 없었다
Peter Cordes

1
네, 것 같습니다 \\r(물론 \r웹 브라우저 렌더링 할 때이 제대로 번역하는 파일 이름의 컴파일러가 출력) 부분. 사용 p.generic_string()일을하지만 백 슬래시는 슬래시입니다.
Michael Petch 2016

5

Visual C ++에서 출력 파일 아래의 프로젝트 옵션에는 소스 코드와 함께 ASM 목록을 출력하는 옵션이 있습니다. 따라서 C / C ++ 소스 코드와 결과 ASM이 모두 동일한 파일에 표시됩니다.


5

MSVC의 경우 링커를 사용할 수 있습니다.

link.exe / dump / linenumbers / disasm /out:foo.dis foo.dll

기호를 얻으려면 foo.pdb를 사용할 수 있어야합니다.


1

Red Gate의 .NET Reflector 는 몇 번 이상 저를 도왔던 꽤 멋진 도구입니다. MSIL을 쉽게 보여주는 것 외에이 유틸리티의 장점은 많은 타사 DLL을 분석하고 Reflector가 MSIL을 C # 및 VB로 변환하도록 할 수 있다는 것입니다.

나는 코드가 소스만큼 명확 할 것이라고 약속하지는 않지만 코드를 따르는 데 많은 문제가 없어야합니다.


2
참고 : 어셈블러 asm 에서처럼 디스 어셈블리하지 않도록 관리되는 어셈블리에만 적용됩니다.
sean e

좋은 지적, 내가로 읽기 "두 줄의 코드 어셈블리 같다"대신 "두 줄의 코드 어셈블리에서 동일"
데이브 L

Visual C ++ 링커 또는 컴파일러가 아닌 dotnet 앱에서만 작동합니다.
무하마드 알리

1

어셈블리 코드를보기 위해 디버깅에 대해 이야기하는 경우 가장 쉬운 방법은 Debug-> Windows-> Disassembly (또는 Alt-8)입니다. 이렇게하면 호출 된 함수로 들어가 디스 어셈블리에 머물 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.