2017-11-13 73 views
1
int x = 5; 

void foo() 
{ 
    long unsigned r[8]; 
    memset(&r, 0, sizeof(long unsigned) * 8); 

    __asm { 

    pushad; 

    pop r[7]; 
    pop r[6]; 
    pop r[5]; 
    pop r[4]; 
    pop r[3]; 
    pop r[2]; 
    pop r[1]; 
    pop r[0]; 
    } 

    printf("Register values: \n"); 

    printf("eax: %lu\n", r[0]); 
    printf("ecx: %lu\n", r[1]); 
    printf("edx: %lu\n", r[2]); 
    printf("ebx: %lu\n", r[3]); 
    printf("esp: %lu\n", r[4]); 
    printf("ebp: %lu\n", r[5]); 
    printf("esi: %lu\n", r[6]); 
    printf("edi: %lu\n", r[7]); 

    if (--x) { foo(); } 
} 

int main() 
{ 
    foo(); 
    return 0; 
} 

방금 ​​누름/푸시 동작에 대해 배웠고 GPR이 어떻게 변경되는지 확인하려고합니다. 그러나 각 foo() 호출 44에 의해 내림차순으로 번호를 인쇄하는 r [0] 제외한 모든 이들에 대해 0 인쇄물을 받고있는 것 같습니다. 그 맞습니까?재귀 함수에서 누름 단추를 사용할 때 스택 포인터가 증가하지 않는 것 같음

내가 알기로는 새로운 기능을 호출 할 때마다 esp 레지스터가 움직이지 않아야합니까?

+1

일반적으로 'pushad' /'popad'를 사용하지 마십시오. 그들은 느리고 거의 모든 레지스터를 저장/복원 할 필요가 거의 없습니다. (일반적으로 함수는 eax/ecx/edx를 망칠 수 있습니다). 또한 MSVC 스타일의 인라인 asm에서는 레지스터를 직접 저장/복원 할 필요가 없습니다. 컴파일러는 저장이 필요할 경우 사용하는 레지스터를 저장합니다. (코드가 이미'ebx','esi' 등을 저장 한 더 큰 함수로 인라인 되었다면) –

+0

@PeterCordes 아, 알겠습니다. 우리가 제공 한 사용자 수준의 스레딩 과제는 pushad와 popad (esp, ebp 및 eip 이외의 레지스터는 거의 알지 못함) 만 다루었 기 때문에 대부분의 사람들이이 작업을 수행하고 있습니다. – ozma

답변

2

이하지 않습니다 확실히 당신이 원하는 무엇을 수행

pop r[7]; 
pop r[6]; 
pop r[5]; 
pop r[4]; 
pop r[3]; 
pop r[2]; 
pop r[1]; 
pop r[0]; 

이것은 실제로 배열 r 각 LONG의 주소를 계산하고 해당 위치에 값을 팝업하지 않습니다. 그것은 다음과 같이 쓰여졌을 것입니다 :

pop [r+7]; 
pop [r+6]; 
pop [r+5]; 
pop [r+4]; 
pop [r+3]; 
pop [r+2]; 
pop [r+1]; 
pop [r+0]; 

인라인 어셈블리는 배열 데이터 요소의 크기를 고려하지 않습니다. 배열의 기본에 값을 추가하면 인덱스가 바이트 단위로 증가합니다.

무슨 일이 일어 났는지 더 분명 할 수 있습니다. r은 배열의 기본 주소가됩니다 (스택에 있기 때문에 ebp에 상대적입니다). r+0은 첫 번째 바이트의 위치이고, r+1은 두 번째 바이트의 위치입니다. 수학을 수행하고 각 LONG에 대한 색인을 계산해야합니다. 그래서 다음과 같이 보일 것입니다.

pop r[28]; 
pop r[24]; 
pop r[20]; 
pop r[16]; 
pop r[12]; 
pop r[8]; 
pop r[4]; 
pop r[0]; 
+0

굉장합니다, 고마워요! 그게 정확히 문제였습니다. – ozma