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에서 어떻게 바꿔야 할까요?
댓글 달기