다음 C 코드를 작성했습니다. 그러나 런타임에서 변수에 대한 잘못된 값을 제공 sb
했기 때문에 GDB로 디버깅하려고 시도했으며 int 나누기 E(vdes->addr, bs)
( #define E(X,Y) X/Y
) 의 어셈블리 코드 가 완전히 이해하기 어렵고 옳은 일을하지 않는 것 같습니다.
파일 : main.c
typedef struct virtual_file_descriptor
{
int dfb;
int addr;
} vfd;
vfd vdes;
if(!strcmp(argv[1], "write")){
vdes.dfb = atoi(argv[2]);
vdes.addr = atoi(argv[3]);
vwrite(&vdes, inbuffer, atoi(argv[4]));
}
파일 : vwrite.c
#define E(X,Y) X/Y
#define bs sizeof(D_Record)*MAX_BLOCK_ENTRIES
int vwrite(vfd *vdes, char *buffer, int size){
if(!vdes)
return -1;
int sb, nb, offset;
sb = E(vdes->addr, bs) + 1; // i did 140/280 => wrong result
offset = vdes->addr - (sb - 1) * bs;
printf("size=%d bs=%d addr=%d sb=%d offset=%d\n\n", size, bs, vdes->addr, sb, offset);
}
int 디비전을 위해 생성 된 어셈블리 언어는 다음과 같습니다 (그것이 잘못되었으며 산술 분할을 수행하는 노래를 포함하지 않음).
(gdb) n
58 sb = E(vdes->addr, bs) + 1;
(gdb) x/10i $pc
=> 0x80001c3d <vwrite+39>: mov 0x8(%ebp),%eax
0x80001c40 <vwrite+42>: mov 0x4(%eax),%eax
0x80001c43 <vwrite+45>: shr $0x2,%eax
0x80001c46 <vwrite+48>: mov $0x24924925,%edx
0x80001c4b <vwrite+53>: mul %edx
0x80001c4d <vwrite+55>: mov %edx,%eax
0x80001c4f <vwrite+57>: shl $0x2,%eax
0x80001c52 <vwrite+60>: add %edx,%eax
0x80001c54 <vwrite+62>: add %eax,%eax
0x80001c56 <vwrite+64>: add $0x1,%eax
0x80001c59 <vwrite+67>: mov %eax,-0x2c(%ebp)
0x80001c5c <vwrite+70>: mov 0x8(%ebp),%eax
0x80001c5f <vwrite+73>: mov 0x4(%eax),%eax
0x80001c62 <vwrite+76>: mov %eax,%edx
동일한 코드 시퀀스를 새 독립 실행 형 파일에 복사했는데 모든 것이 잘 작동합니다 (결과 수정 및 어셈블리 코드 수정). 그래서 왜 첫 번째 코드가 작동하지 않는지 궁금해졌습니다.
파일 : test.c
#define E(X,Y) X/Y
int main(int argc, char **argv){
int sb = E(atoi(argv[1]), atoi(argv[2]));
return 0;
}
이전 코드에 대해 생성 된 어셈블리 코드 (정확하게 이해하기 쉽고 int 디비전을 수행하기위한 올바른 코드) :
.
.
call atoi
.
call atoi
.
.
0x800005db <main+75>: mov %eax,%ecx
0x800005dd <main+77>: mov %edi,%eax
0x800005df <main+79>: cltd
0x800005e0 <main+80>: idiv %ecx
0x800005e2 <main+82>: mov %eax,-0x1c(%ebp)
원래 질문은
#define bs 280
나중에 다음으로 변경되었습니다.
#define bs sizeof(D_Record)*MAX_BLOCK_ENTRIES
다른 표현식에서 bs를 사용하는 문제를 방지하려면 다음과 같이해야합니다.
#define bs (sizeof(D_Record)*MAX_BLOCK_ENTRIES)
E에 대한 정의는 다음과 같아야합니다.
#define E(X,Y) ((X)/(Y))
생성 된 어셈블리 코드는
#define bs sizeof(D_Record)*MAX_BLOCK_ENTRIES
#define E(X,Y) X/Y
... E(vdes->addr, bs) ...
따라서 shift를 사용하여 28로 나누고 곱한 다음 10을 곱하십시오.
mov 0x4(%eax),%eax ;eax = dividend
shr $0x2,%eax ;eax = dividend/4 (pre shift)
mov $0x24924925,%edx ;edx = multiply constant
mul %edx ;edx = dividend/28 (no post shift)
mov %edx,%eax ;eax = (dividend/28)*10
shl $0x2,%eax
add %edx,%eax
add %eax,%eax
eax = edx * 10 시퀀스의 경우 lea가 사용되지 않은 이유를 잘 모르겠습니다.
lea (%edx,%edx,2),eax ;eax = edx*5
add %eax,%eax ;eax = edx*10
상수로 나누기가 곱셈과 시프트로 변환되는 방법에 대한 설명이있는 이전 스레드에 연결합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다