output의 구성을 나타낸다. "=&S" (d0)는 d0를 'si' 레지스터에 저장하는 것이고
"=&D" (d1)은 d1을 'di' 레지스터에 저장하란 것이고 "=&a" (d2)는 d2를 'a'
레지스터에 저장하란 것이다.
test.s에 의하면 어셈블리 코드가 실행된 후 output으로 d0, d1, d2가 있는데
#NO_APP 바로 밑의 3줄이 이 역할을 한다. d2는 %ebx에 할당됐음을 알 수 있다.
:"0" (src),"1" (dest)
input의 구성을 나타낸다. "0" (src)는 src가 0번째 오퍼랜드와 같은 위치를 점유하란 말로
%0인 d0를 의미한다. 또 d0가 si를 사용하므로 결국 si의 초기 값이 src가된다. dest는 %1인
di에 입력된다.
test.s에 의하면 #APP 바로 전의 두줄이 input에 해당하고 %esi와 %edi에 src, dest를
입력해 준다.
: "memory"
clobber에 지정된 "memory"는 컴파일러에게 어셈블리코드가 메모리의 어딘가를 변경한다고
가르쳐 주는 것이다. 이 것을 사용하지 않으면 어셈블리코드에서 메모리의 내용을 변경하는
것을 컴파일러는 전혀 알 수 없다. 잘 못하면 어셈블리에서 고친 값과 다른 값을 컴파일러
는 사용하고 있을 가능성도 있다. "memory"를 명시해 주면 컴파일러는 어셈블리 코드를 실
행하기 전/후에 레지스터에 저장되어 있는 모든 변수의 값을 갱신하도록 한다.
"1:\tlodsb\n\t"
1:은 label을 의미한다. loadsb 명령으로 al 레지스터에 es:esi의 내용을 읽어 온다.
여기서 src의 내용을 읽어 온다. 명령 실행후 esi는 자동으로 1이 증가한다(바이트 단위로
읽기 때문).
"stosb\n\t"
al의 값을 es:edi에 저장한다. edi도 명령 실행 후 1 증가한다.
"testb %%al,%%al\n\t"
al의 내용이 0인지 테스트한다. 스트링을 복사할 땐 NULL 캐릭터가 나올 때 까지 복사하기
때문에 0인지 판별한다.
C.2. 사례 분석
리눅스 커널에 이미 사용된 수 많은 예를 통해 어떤 식으로 인라인 어셈블리가 사용됐는지 알아보자.
C.2.1. strcpy()
아래 소스 코드는 include/asm-i386/string.h에 있는 strcpy() 함수를 가져와 컴파일 해보기 위해 조금 추가한 코드다.
컴파일은 'gcc -S -c test.c'라고 한다. 그러면 test.s가 생길 것이다. test.s는 다음과 같다.
인라인 어셈블리는 #APP와 #NO_APP사이에 존재한다.
output의 구성을 나타낸다. "=&S" (d0)는 d0를 'si' 레지스터에 저장하는 것이고 "=&D" (d1)은 d1을 'di' 레지스터에 저장하란 것이고 "=&a" (d2)는 d2를 'a' 레지스터에 저장하란 것이다.
test.s에 의하면 어셈블리 코드가 실행된 후 output으로 d0, d1, d2가 있는데 #NO_APP 바로 밑의 3줄이 이 역할을 한다. d2는 %ebx에 할당됐음을 알 수 있다.
input의 구성을 나타낸다. "0" (src)는 src가 0번째 오퍼랜드와 같은 위치를 점유하란 말로 %0인 d0를 의미한다. 또 d0가 si를 사용하므로 결국 si의 초기 값이 src가된다. dest는 %1인 di에 입력된다.
test.s에 의하면 #APP 바로 전의 두줄이 input에 해당하고 %esi와 %edi에 src, dest를 입력해 준다.
clobber에 지정된 "memory"는 컴파일러에게 어셈블리코드가 메모리의 어딘가를 변경한다고 가르쳐 주는 것이다. 이 것을 사용하지 않으면 어셈블리코드에서 메모리의 내용을 변경하는 것을 컴파일러는 전혀 알 수 없다. 잘 못하면 어셈블리에서 고친 값과 다른 값을 컴파일러 는 사용하고 있을 가능성도 있다. "memory"를 명시해 주면 컴파일러는 어셈블리 코드를 실 행하기 전/후에 레지스터에 저장되어 있는 모든 변수의 값을 갱신하도록 한다.
1:은 label을 의미한다. loadsb 명령으로 al 레지스터에 es:esi의 내용을 읽어 온다. 여기서 src의 내용을 읽어 온다. 명령 실행후 esi는 자동으로 1이 증가한다(바이트 단위로 읽기 때문).
al의 값을 es:edi에 저장한다. edi도 명령 실행 후 1 증가한다.
al의 내용이 0인지 테스트한다. 스트링을 복사할 땐 NULL 캐릭터가 나올 때 까지 복사하기 때문에 0인지 판별한다.
0이 아닌 경우, 즉 NULL 캐릭터가 아닌 경우 계속해서 복사한다.
C.2.2. _set_gate()
arch/i386/kernel/trap.c에 있는 _set_gate()의 내용을 가져다 컴파일 하기 위해 약간 변경한 것이다.
'gcc -S -c sg.c'로 컴파일한 것은 다음과 같다.
input으로 정의된 것 들이다. "3", "2"는 각각 %3(__d0), %2(__d1)로 대응되도록 한다. $APP 전의 3줄 중 윗 2줄이 "3", "2"에 해당하는 것들이다.
output으로 정의된 것 들. %0은 값이 0이되고(main에서 _set_gate(0, 1, 2, 3)으로 했기 때문에) %1은 4가 된다.
Recent Posts
Archive Posts
Tags