리눅스 커널 어셈블리고수님의 지도 바랍니다.
리눅스 커널 2.41에서 보면 현재 task를 저장하는Function switch_to가 있
잖아요?
그 소스 내에 있는 어셈블리 내용중하나를 질문합니다.
%0 == last %1 == next , %2 ==prev인것같은데요 %3 , %4는 무엇을 가리키
죠?
아니면 제가 잘못 알고 있나요?
빠른 답변 바랍니다.
#define switch_to(prev,next,last) do {\
asm volatile("pushl %%esi\n\t"\
"pushl %%edi\n\t"\
"pushl %%ebp\n\t"\
"movl %%esp,%0\n\t"/* save ESP */\
"movl %3,%%esp\n\t"/* restore ESP */\
"movl $1f,%1\n\t"/* save EIP */ \
"pushl %4\n\t"/* restore EIP */ \
"jmp __switch_to\n"\
"1\t"\
"popl %%ebp\n\t"\
"popl %%edi\n\t"\
"popl %%esi\n\t"\
"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
"=b" (last) \
"m" (next->thread.esp),"m" (next->thread.eip), \
"a" (prev), "d" (next), \
"b" (prev)); \
} while (0)
Re: 고수 아닙니다.
저 고수 아닙니다.
문서 뒤적거려서 적어 드리겠습니다.
저의 답이 '정확' 하다는 보장은 해드리지 못합니다.
문서를 직접 찾아보시고 다시 한번 검증해 보세요 )
#define switch_to(prev,next,last) do {\
asm volatile("pushl %%esi\n\t"\
"pushl %%edi\n\t"\
"pushl %%ebp\n\t"\
"movl %%esp,%0\n\t"/* save ESP */\
"movl %3,%%esp\n\t"/* restore ESP */\
"movl $1f,%1\n\t"/* save EIP */ \
"pushl %4\n\t"/* restore EIP */ \
"jmp __switch_to\n"\
"1\t"\
"popl %%ebp\n\t"\
"popl %%edi\n\t"\
"popl %%esi\n\t"\
"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
"=b" (last) \
"m" (next->thread.esp),"m" (next->thread.eip), \
"a" (prev), "d" (next), \
"b" (prev)); \
} while (0)
"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
"=b" (last) \
위의 두줄은, 어셈블리 루틴에서 writing 을 하는 레지스터 및 메모리 주
소를
적어 주는 부분입니다. '출력부' 라고 부르기도 합니다.
=m 의 "=" 은, 여기서 지정하는 인자가 write only 인자라고 지정해 주는
것이고,
"m" 은, 그 인자의 위치가 메모리에 있을 것이라는 것을 알려 주는(컴파일
러에게) 것입니다.
=b 의 "b" 는 last 의 값이 b 레지스터 (i386 에서는 ebx 레지스터) 에 들
어갈 것을
지정해 주는 것입니다.
여기서, %0 은, prev->thread.esp. %1 은 prev->thread.eip, %2 는 last
를 가리킵니다.
"m" (next->thread.esp),"m" (next->thread.eip), \
"a" (prev), "d" (next), \
"b" (prev)); \
위의 세 줄은 어셈블리 루틴에서 reading 을 하는 주소를 적어 주는 부분
입니다.
'입력부'라고 부르기도 합니다.
역시 "m" 은 메모리 operand 임을 나타냅니다.
그리고, "a" 는 i386 에서 "a" 레지스터, 즉, eax 를 가리킵니다.
"d" 는 edx, "b" 는 ebx 입니다.
각각 %3 은, next->thread.esp. %4 는 next->thread.esp, %5 는 prev....
와 같은 식으로
각각의 operand 들에 %0 부터 차례로 번호를 붙여나가서 지칭하게 됩니다.
context switch 가 일어나게 하려면, 당연히 esp 를 푸시하고, 팝하는동
작, eip 를 푸시하고
팝 하는 등의 동작이 필요하게 됩니다.
여기서 esp 를 다시 읽어 들이는 것은, context switch 의 결과로 실행될
process 의 context
가 사용하던 스택 포인터를 복구함으로써 스택의 change 를 하는 것이고,
스택이 바뀐 상태에서 이전에 push 되었던 eip 를 pop 함으로써 실행의 흐
름이 복구되는
것입니다.
참고하실 문헌들로는,
Assembly-howto
Assembly-example
gcc-inline assembly howto
(위의 세가지는 번역된 문서가 kldp 에 있습니다)
gcc-manual
(http//gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_16.html#SEC175) 등이
있습니다.
댓글 달기