I have written the following C code. But in runtime it gave me incorrect values for the variable sb
, so i tried to debug it with GDB and i found out that the assembly code for the int division E(vdes->addr, bs)
(#define E(X,Y) X/Y
) was completely incomprehensible and seems to be not doing the right thing.
File: 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]));
}
File: 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);
}
The assembly language generated for the int devision was (Which is wrong and doesn't contain any sings of doing an arithmetic division) :
(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
I copied the same code sequence to a new standalone file and everything works fine (Correct results and correct assembly code). So i came to wonder why doesn't the first code work ?
File: 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;
}
Assembly code generated for previous code (which is a nicely understandable and correct code for doing int devision):
.
.
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)