2011-01-25 3 views
17

, 나는 nopw 명령의 기계 코드 인코딩 작동 방식을 이해하기 위해 노력하고있어 : http://john.freml.in/amd64-nopl에서 "nopw"에 대한 몇 가지 논의가있다AMD64 - nopw 조립 지침? 이 컴파일러 출력에서 ​​

00000000004004d0 <main>: 
    4004d0:  eb fe     jmp 4004d0 <main> 
    4004d2:  66 66 66 66 66 2e 0f nopw %cs:0x0(%rax,%rax,1) 
    4004d9:  1f 84 00 00 00 00 00 

. 아무도 4004d2-4004e0의 의미를 설명 할 수 있습니까? opcode 목록을 보면, 66 .. 코드가 멀티 바이트 확장임을 알 수 있습니다. 나는 몇 시간 동안 opcode리스트를 알아 내려하지 않으면 내가 여기있는 것보다 더 나은 대답을 얻을 수 있다고 생각한다.


는 ASM 출력 간단한 무한 루프까지 최적화 C의 다음 (미친) 코드 있음 :

long i = 0; 

main() { 
    recurse(); 
} 

recurse() { 
    i++; 
    recurse(); 
} 

gcc -O2 컴파일 컴파일러는 무한 재귀 교대 인식 그것은 무한 루프로; 실제로는 실제로이 작업을 수행하므로 recurse() 함수를 호출하지 않고 main()에서 실제로 반복됩니다.


편집자 주 : NOP가있는 패딩 기능은 무한 루프에만 해당되지 않습니다. 여기에 NOP 길이의 범위가있는 함수 세트가 있습니다. on the Godbolt compiler explorer.

+0

여기서 우리는 단지 임의의 정크 패딩을보고 있습니까? –

+1

어쩌면! 나는 정말로 모른다! 그것은 그것의 모든 아름다움입니다! WHEEE. 정말로, 비록 링크드로부터 프로세서가 속도 최적화를위한 하나의 명령으로 블록을 로딩 할 것이지만, 'jmp'덕분에 그렇지 않습니다. 나는 단지 그것의 의미를 얻는다. 0x90이 무엇인지는 알고 있지만,'66 .. ..'로 무슨 일이 일어나고 있는지, 왜 72 비트인지 알지 못합니다. –

+1

그것은 여기에있는 이유는 아니지만, [내, 당신이 가지고있는 이상한 NOP들! - The Old New Thing] (http://blogs.msdn.com/b/oldnewthing/archive/2011/01/12/10114521.aspx) 흥미로운 읽기. – ephemient

답변

20

0x66 바이트는 "Operand-Size Override"접두사입니다. 이 중 하나 이상을 갖는 것은 하나를 갖는 것과 동일합니다.

0x2e은 64 비트 모드에서 '널 프리픽스'입니다. 그렇지 않으면 CS : 세그먼트가 오버라이드되어 어셈블리 니모닉에 표시됩니다.

0x0f 0x1f

0x84ModRM byte 인 ModRM 바이트를 취하는 NOP하는 2 바이트 오피 인 5 개의 바이트를 사용 어드레싱 모드 이때 코드이다.

일부 CPU는 여러 개의 접두어 (예 : 3 개 이상)가있는 명령어를 디코딩하는 속도가 느리기 때문에 SIB + disp32를 지정하는 ModRM 바이트가 5 개 이상의 접두어 바이트보다 추가 5 바이트를 사용하는 것이 훨씬 더 좋습니다.

AMD K8 decoders in Agner Fog's microarch pdf

:

명령어 디코더 각각의 클럭 사이클 당 세 개의 접두사를 처리 할 수 ​​있습니다. 즉, 각각 3 개의 접두사가있는 3 개의 명령어는 동일한 클럭 사이클에서 디코드 될 수 있습니다. 접두사가 4 - 6 인 명령어 인 은 디코딩 할 때 추가 클럭 사이클을 필요로합니다.


기본적으로, 그 바이트 어쨌든 실행되지 얻을 않습니다 하나 개의 긴 NOP 명령입니다. 컴파일러가 .p2align 4 지시어를 방출 했으므로 다음 함수가 16 바이트 경계에 정렬되도록 보장하기 위해 어셈블러에 NOP가 추가되었습니다.gcc's default for x86 is
-falign-functions=16
. 실행될 NOP의 경우 long-NOP의 최적 선택은 마이크로 아키텍처에 따라 다릅니다. Intel Silvermont 나 AMD K8과 같은 많은 접두어를 사용하는 마이크로 아키텍처의 경우 3 개의 접두어가있는 두 개의 NOP가 각각 더 빨리 해독되었을 수 있습니다.

블로그 기사에 (http://john.freml.in/amd64-nopl)에 링크 된 질문은 컴파일러가 1 바이트 0x90 NOP 명령어의 묶음 대신 복잡한 단일 NOP 명령어를 사용하는 이유를 설명합니다.

당신은 AMD의 기술 심판 문서의 지시 인코딩에 대한 세부 사항을 찾을 수 있습니다

  • http://developer.amd.com/documentation/guides/pages/default.aspx#manuals
    • 주로에서 "AMD64 아키텍처 프로그래머의 설명서 제 3 권 : 일반 목적 및 시스템 지침". 나는 인텔의 x64 아키텍쳐에 대한 기술 레퍼런스가 똑같은 정보를 가질 것이라고 확신한다.

    +0

    ModRM 바이트 의미 다시 ... http://ref.x86asm.net/coder64.html#x0F1F는 ModRM 바이트를 Hintable NOP에 사용되는 것으로 나열하며 다음을 참조합니다. 1. 미국 특허 5,701,442를 참조하십시오. 2. sandpile. org - IA-32 아키텍처 - opcode 그룹. 나는 그걸 확인하지 않았지만 당신이 신경 쓸 경우에 대비해. – Bahbar

    +0

    이것은 NOP이므로 mod/rm 바이트는 아무 것도하지 않습니다. 이 명령어는 디코더가 신속하게 디코딩 할 수있는 방법으로 다양한 명령어 길이를 허용하는 방법입니다. 많은 접두사를 디코딩하는 것은 일부 CPU에서는 느리기 때문에 '66'피연산자 크기 접두사를 5 번 더 반복하는 것은 SIB + disp32를 사용하는 주소 지정 모드를 코딩하는 mod/rm보다 훨씬 나쁩니다. –

    1

    이것은 분기 지연 명령어 일뿐입니다.

    -3

    나는 nopw가 쓰레기라는 것을 믿는다. 나는 당신의 프로그램에서 결코 읽히지 않는다. 따라서 그것을 증가시킬 필요가 없다.

    +0

    'i'는 실패했을 때 스택 크기를 확인하는 편리한 방법을 제공했습니다. Gdb는 제한된 지식이있는 한 "스택 크기의 인쇄"키를 가지고 있지 않습니다. 최적화 레벨이 올라가면 컴파일러가 증가분을 제거하는 것을 보는 것이 더 재미 있습니다. 이 프로그램은 의도적으로 "정신 나간"입니다. –

    +0

    제 요점은 컴파일러가 그것을 최적화했다는 것입니다. –

    +0

    질문은 그것에 관한 것이 아닙니다. 질문의 요점은 왜 'nop' (여기에'nopw')이 그렇게 나오는가하는 것입니다. 표준'nop'은 0x90이며 그냥 반복됩니다. 사용하지 않는 변수로'i'를 넣는 것은 코드에서 다루지 않아도 유용하고 외부 적으로 유용했습니다. –

    2

    어셈블러 (컴파일러가 아님)는 다음 정렬 경계까지 코드를 찾을 수있는 가장 긴 NOP 명령으로 코드화합니다. 이것은 당신이보고있는 것입니다.