asm문법에 대하여 질문이 있습니다.(mmx 샘플)
글쓴이: cho's / 작성시간: 월, 2003/08/18 - 4:16오후
간단하게 8bit를 16bit로 바꿔서 arrange해주는 함수 입니다.
현재 사용하고 있는데 제가 제대로 한건지 궁금한 점이 몇가지 있어서요.
소스는 이상없이 돌아가고 있습니다. __WIN32__를 보고 linux의 att로 변환한 겁니다. 그냥 에러 안날때 까지 이것 저것 해보고 결과값이 같이 나오는지 확인해서 짠겁니다. mmx_att함수를 제대로 변환한 건지, 문제는 없는지 알고 싶습니다.
궁금한 점은
1] add instruction의 경우
subl처럼 빼는데(이경우 더하는데)에도 쓰이지만 아래 소스에 보시면 Offset을 증가하는데도 쓰입니다. 이렇게도 쓰이는 건가요?
"addl $16, %%edi \n\t" // dst, add is plus or offset? "addl $4, %%edx \n\t" // pidxp++
2]
배열의 인덱스를 (%%esi, %%ebx)형태로 쓰나요? 어셈블리 문서에서 보면
Intel: [eax+1] , AT&T:1(%%eax)이런식으로 나와 있어서 처음에는 %%ebx(%%esi)이런식으로 했더니 에러가 나더라구요.
그리고 Intel:[ebx+eax*4+array], AT&T:array(%ebx, %eax, 4)이렇게 나와 있어서 이것저것 해봤는데 에러가 나더군요. 그래서 최종적으로 아래와 같이 해결했습니다. 왜 이런건가요?
"movq (%%esi, %%ebx), %%mm0 \n\t" //p[idx], %%mm0,
3]memory operand를 어떤경우에 쓰는지 잘 감이 안옵니다. 그리고 값이 변할수 있는 모든 변수는 output변수들쪽에 넣어야만 하는지요?현재 소스에서는 input쪽에 넣었는데 이상이 없는것 같습니다.
#include <stdio.h> #include <stdlib.h> void arrange_blk_int(short *pdst, int *pidxp, unsigned char *p) { int i,idx; for(i=0;i<64;i+=8) { idx= *pidxp; pdst[i] = p[idx]; pdst[i+1] = p[idx+1]; pdst[i+2] = p[idx+2]; pdst[i+3] = p[idx+3]; pdst[i+4] = p[idx+4]; pdst[i+5] = p[idx+5]; pdst[i+6] = p[idx+6]; pdst[i+7] = p[idx+7]; pidxp++; } printf("result, pidxp:%d\n", *pidxp); for(i=0; i<64; i+=8) // for debug { if((i%8) == 0) printf("\n"); printf("%d\t", pdst[i]); } } #ifdef __WIN32__ void arrange_blk_mmx_intel(short *pdst, int *pidxp, unsigned char *p) { __asm { mov esi,p ;src mov edi,pdst ;dst mov edx,pidxp ;index mov ecx,8 pxor mm7,mm7 ;mm7= 0 dorepeat: mov ebx,[edx] movq mm0,dword ptr [esi+ebx] ;4 bytes punpcklbw mm0,mm7 ;make short movq qword ptr [edi],mm0 movq mm0,dword ptr [esi+ebx+4] ;4 bytes punpcklbw mm0,mm7 ;make short movq qword ptr [edi+8],mm0 add edi,16 ;dst add edx,4 ;idxp sub ecx,1 cmp ecx,0 jg dorepeat emms } } #endif void arrange_blk_mmx_att(short *pdst, int *pidxp, unsigned char *p) { int i; asm volatile( "movl %2, %%esi \n\t" // *p "movl %1, %%edx \n\t" // *pidxp "movl %0, %%edi \n\t" // *pdst "movl $8, %%ecx \n\t" // use for loop "pxor %%mm7, %%mm7 \n\t" // mm7 = 0 "1: \n\t" "movl (%%edx), %%ebx \n\t" // idx = *pidxp "movq (%%esi, %%ebx), %%mm0 \n\t" //p[idx], %%mm0, 4bytes "punpcklbw %%mm7, %%mm0 \n\t" "movq %%mm0, (%%edi) \n\t" // pdst = mm0 "movq 4(%%esi, %%ebx), %%mm0 \n\t" // p[idx]+4, %%mm0, 4bytes "punpcklbw %%mm7, %%mm0 \n\t" "movq %%mm0, 8(%%edi) \n\t" //edi's offset 8 "addl $16, %%edi \n\t" // dst, add is plus or offset? "addl $4, %%edx \n\t" // pidxp++ "subl $1, %%ecx \n\t" "cmpl $0, %%ecx \n\t" "jg 1b \n\t" //jump if greater "emms \n\t" :"+g" (pdst) // +g or +r or +m? g는 global이고 r은 register이고 m은 메모리라는 건 알겠는데 어느 순간에 memory를 쓰나요? 현재상황에서 m을 써도 될까요? 그리고 값이 변하는건 pdst지만 pidxp도 포인터가 증가하니까 output쪽에 놔야 할까요? :"g" (pidxp), "g" (p) : //"memory" 와 같은 옵션을 현재 안집어 넣었는데 집어넣어야 할까요? ); printf("result\n"); for(i=0; i<64; i+=8) // for debug { if((i%8) == 0) printf("\n"); printf("%d\t", pdst[i]); } } unsigned char src[64*8]; short dst[64*8]; int main(int argc, char* argv[]) { int i; int idx[3][4]; for(i = 0; i < 64*8; i++) src[i] = (unsigned char)i; idx[0][0] = 0; idx[0][1] = 8; idx[0][2] = 16; idx[0][3] = 24; idx[1][0] = 32; idx[1][1] = 40; idx[1][2] = 48; idx[1][3] = 48; idx[2][0] = 64; idx[2][1] = 72; idx[2][2] = 80; idx[2][3] = 88; //arrange_blk_int(dst, idx[0], src); arrange_blk_mmx_att(dst, idx[0], src); }
읽어주셔서 고맙습니다.
Forums:
2]번 질문에 대한 상세
질문]문 Intel:[ebx+eax*4+array], AT&T:array(%ebx, %eax, 4)이렇게 나와 있어서 이것저것 해봤는데 에러가 나더군요. 그래서 최종적으로 아래와 같이 해결했습니다. 왜 이런건가요?
상세 질문]
Referencing memory
*AT&T : immed32(basepointer , indexpointer, indexscale)
*Intel : [basepointer + indexpointer* indexscale + immed32]
이 경우는 Intel:[ebx+eax]인 경우 [ebx+eax*1+0]으로 생각하면
AT&T로 변환하면 0(%%ebx, %%eax, 1) 이어야 하지 않나요?
참고로 Intel에서 [esi+ebx+4]의 경우는 4(%%esi, %%ebx)로 바꿨습니다. 다. 잘 되더군요. 대충 이렇게 하면 되겠다라는 것은 알겠습니다.
위의 3가지 질문에 대해서 간략하게나마 설명 부탁드립니다.
좋은 하루 되세요.
추가로 질문입니다.
Intel에서
이 경우 AT&T에서 어떻게 바꿔야 할까요?
댓글 달기