汇编结构体数组寻址

本文详细介绍了如何在汇编语言中通过左移、加法和结构体内部偏移来实现对结构体数组的寻址操作。具体步骤包括:1) 左移和加法计算数组下标;2) 结合结构体首地址和计算出的偏移获取特定元素地址。以一个包含整数和字符的结构体为例,展示了读写操作的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值