1、左移
2、加一定倍值
3、再左移,得到数组下标形成偏移
4、取首地址
5、首地址 + 数组下标形成偏移 + 结构体内部偏移得到欲存取的地址
routine
shl ...
add ...
shl ...
mov offset xxxxx
call atoi函数取得一个整数,将这个整数按照68字节一个结构体进行寻址以16 bit字类型写入对应结构体的第四个字节处
写入
.text:0802A6E9 call _atoi
.text:0802A6EE add esp, 4
.text:0802A6F1 mov [ebp+tmp], eax ;保存得到的整数(返回值)
.text:0802A6F7 mov eax, [ebp+index] ;[ebp+index]保存欲寻址第index个结构体
.text:0802A6FA mov [ebp+struct_offset], eax ;[ebp+index] = [ebp+tmp] = eax = index(第index个item)
.text:0802A700 mov ebx, [ebp+struct_offset]
.text:0802A706 mov ecx, ebx
.text:0802A708 shl ecx, 4 ;ecx = 16 * [ebp+index]
.text:0802A70B add ecx, [ebp+struct_offset] ;ecx = 17 * [ebp+index]
.text:0802A711 lea edx, ds:0[ecx*4] ;edx = 68 * [ebp+index] 完成第index个item偏移地址的计算
.text:0802A718 mov [ebp+struct_offset], edx ;保存偏移地址
.text:0802A71E mov ecx, offset memory ;取存放结构体数组内存区域的首地址
.text:0802A723 mov eax, [ebp+tmp] ;取atoi函数的返回值
.text:0802A729 mov edi, [ebp+struct_offset] ;取偏移地址
.text:0802A72F mov [edi+ecx+4], ax ;atoi返回值以16 bit字形式写入对应结构体的第四个字节起始处
读出:
.text:0802A734 mov edx, [ebp+index]
.text:0802A737 mov [ebp+tmp], edx
.text:0802A73D mov ecx, [ebp+tmp]
.text:0802A743 mov edi, ecx
.text:0802A745 shl edi, 4 ;第一次移位得到16*index
.text:0802A748 mov [ebp+struct_offset], edi
.text:0802A74E mov eax, [ebp+tmp]
.text:0802A754 add [ebp+struct_offset], eax ;[ebp+struct_offset] = 17 * [ebp+index]
.text:0802A75A mov edx, [ebp+struct_offset]
.text:0802A760 shl edx, 2 ;第二次移位得到68*index
.text:0802A763 mov [ebp+tmp], edx ;[ebp+tmp] = 68 * [ebp+index]
.text:0802A769 mov [ebp+struct_offset], offset memory
.text:0802A773 mov edi, [ebp+struct_offset]
.text:0802A779 mov eax, [ebp+tmp]
.text:0802A77F cmp word ptr [eax+edi+4], 0xff ;将刚才写入的值取出进行比较
临时变量存储的内容可能不一样,基本思想是一次移位后加上一个值后在移位一次,因为分配存储空间的时候会有内存对齐,
移位即可索引任意长度的结构体,如果想找存取结构体中某个域的值只要在最后由首地址和计算出来的偏移地址相加得到的
索引地址后再加上存取字段在结构体中的偏移值即可
源代码
struct item
{
int a;
char ch1;
int b;
char ch2;
int c;
char ch3;
char ch[10];
int d;
};
struct item test[100];
void print(int index)
{
int tmp = test[index].d;
char *p = test[index].ch;
char ctmp = test[index].ch2;
printf("%d/n", tmp);
tmp = test[index].a;
printf("%d/n", tmp);
}
汇编代码
08048540 <print__Fi>:
8048540: push %ebp
8048541: mov %esp,%ebp
8048543: sub $0x18,%esp ;routine
;tmp = test[index].d
8048546: mov 0x8(%ebp),%edx ;argc->edx
8048549: mov %edx,%eax ;eax = edx
804854b: shl $0x3,%eax ;eax = 8 * argc
804854e: add %edx,%eax ;eax = 9 * argc
8048550: shl $0x2,%eax ;eax = 36 * argc
8048553: lea 0x20(%eax),%edx ;结构体内部偏移量为32个字节,取最后的一个int
8048556: mov $0x8049140,%eax ;取test在内存中首地址
804855b: mov (%edx,%eax,1),%eax ;[edx + eax * 1] -> eax 表示寻址方式
804855e: mov %eax,0xfffffffc(%ebp) ;eax -> [ebp - 4] 第一个临时变量,
;p = test[index].ch;
8048561: mov 0x8(%ebp),%edx
8048564: mov %edx,%eax
8048566: shl $0x3,%eax
8048569: add %edx,%eax
804856b: shl $0x2,%eax
804856e: add $0x8049155,%eax ;0x8049140为首地址+21个字节偏移量找到ch 和上面稍有不同
8048573: mov %eax,0xfffffff8(%ebp) ;eax -> [ebp-8] 第二个临时变量
;ctmp = test[index].ch2
8048576: mov 0x8(%ebp),%edx
8048579: mov %edx,%eax
804857b: shl $0x3,%eax
804857e: add %edx,%eax
8048580: lea 0x0(,%eax,4),%edx ;edx = 36 * argc
8048587: mov $0x8049140,%eax
804858c: mov 0xc(%edx,%eax,1),%al ;12个字节结构体内部偏移量
8048590: mov %al,0xfffffff7(%ebp) ;ebp - 9 第三个临时变量
; printf("%d/n", tmp);
8048593: sub $0x8,%esp
8048596: pushl 0xfffffffc(%ebp)
8048599: push $0x80486f8
804859e: call 8048408 <_init+0x48>
80485a3: add $0x10,%esp