32位汇编语言学习笔记(17)--结构体

时间:2021-09-26 01:06:59


结构体成员的访问:

struct rec {

   inti;

   int j;

   int a[3];

   int *p;

};

 

void copy(struct rec *r)

{

   r->j = r->i;

}

 

gcc -O1 -S -m32 struct1.c

 

copy:

       pushl  %ebp

       movl   %esp, %ebp

       movl   8(%ebp), %edx //结构体r的指针

       movl   (%edx), %eax //eax =r->i

       movl   %eax, 4(%edx) //r->j =r->i

       popl   %ebp

       ret

 

结构体之间的拷贝:

struct rec {

   int i;

   int j;

   int a[3];

   int *p;

};

 

void copy(struct rec *sr, struct rec *dr)

{

   *dr= *sr;

}

 

gcc -O1 -S -m32 struct2.c

 

copy:

       pushl  %ebp

       movl   %esp, %ebp

       movl   8(%ebp), %edx //edx = sr

       movl   12(%ebp), %ecx //ecx = dr

       movl   (%edx), %eax //eax =sr->i

       movl   %eax, (%ecx) //dr->I =sr->i

       movl   4(%edx), %eax // eax =sr->j

       movl   %eax, 4(%ecx) //dr->j =sr->j

       movl   8(%edx), %eax //eax =sr->a[0]

       movl   %eax, 8(%ecx)//dr->a[0] = sr->a[0]

       movl   12(%edx), %eax //eax =sr->a[1]

       movl   %eax, 12(%ecx)//dr->a[1] = sr->a[1]

       movl   16(%edx), %eax //eax =sr->a[2]

       movl   %eax, 16(%ecx)//dr->a[2] = sr->a[2]

       movl   20(%edx), %eax //eax =sr->p

       movl   %eax, 20(%ecx) //dr->p= sr->p

       popl   %ebp

       ret

 

int a[3]改成int a[3000],再生成一次汇编代码:

copy:

       pushl  %ebp

       movl   %esp, %ebp

       subl   $24, %esp //esp=esp -24

       movl   $12012, 8(%esp) //esp+8 =12012,结构体的大小

       movl   8(%ebp), %eax //eax = sr

       movl   %eax, 4(%esp) //esp+4 = sr

       movl   12(%ebp), %eax //eax = dr

       movl   %eax, (%esp) //esp = dr

       call   memcpy //调用函数memcpy

       leave //清理栈

       ret

从本例可以看出,如果结构体比较小,结构体间的拷贝就是对构体的每个成员进行赋值。如果结构体很大,需要通过memcpy函数调用来完成拷贝动作。

 

值传递:

struct rec {

   int i;

   int j;

   int a[3000];

   int*p;

};

 

struct rec copy(struct rec *sr, struct rec*dr)

{

   *dr = *sr;

   return *dr;

}

 

gcc -O1 -S -m32 struct3.c

 

copy:

       pushl  %ebp

       movl   %esp, %ebp

       subl   $24, %esp //esp = esp -24

       movl   %ebx, -8(%ebp) // ebp -8 =ebx,备份ebx

       movl   %esi, -4(%ebp) //ebp -4=esi,备份esi

       movl   8(%ebp), %esi //用于返回的结构体临时变量的地址

       movl   16(%ebp), %ebx //ebx = dr

       movl   $12012, 8(%esp) //结构体大小装入esp +8

       movl   12(%ebp), %eax //eax = sr

       movl   %eax, 4(%esp) //sr装入esp+4

       movl   %ebx, (%esp) //dr装入esp

       call   memcpy //调用memcpy

       movl   $12012, 8(%esp) //结构体大小装入esp +8

       movl   %ebx, 4(%esp) //dr装入esp+4,作为源

       movl   %esi, (%esp) //用于返回的结构体临时变量的地址装入esp,作为目的

       call   memmove //调用memmove

       movl   %esi, %eax //用于返回的结构体临时变量的地址装入eax作为返回值

       movl   -8(%ebp), %ebx //恢复ebx

       movl   -4(%ebp), %esi //恢复esi

       movl   %ebp, %esp

       popl   %ebp

       ret    $4 //表示在返回时,除了弹出返回地址外,还要把栈指针上移4个字节,因为在函数调用时调用者多加了一个临时变量的地址作为参数。

 

结构体临时变量应该放在栈中,这样当调用者保存返回值时,还会把结构体临时变量再拷贝一次,等于多做了两次拷贝操作,所以如果把结构体变量作为返回值,效率会很低。

 

结构体的嵌套:

struct prob {

   int *p;

   struct {

       int x;

       int y;

   }s;

   struct prob *next;

};

 

void sp_init(struct prob *sp)

{

   sp->s.x  = sp->s.y;

   sp->p    = &(sp->s.x);

   sp->next = sp;

}

 

gcc -O1 -S -m32 struct4.c

 

sp_init:

       pushl  %ebp

       movl   %esp, %ebp

       movl   8(%ebp), %eax //eax = sp

       movl   8(%eax), %edx // edx = sp->s.y

       movl   %edx, 4(%eax) //sp->s.x= sp->s.y

       leal   4(%eax), %edx // edx =&(sp->s.x)

       movl   %edx, (%eax) // sp->p =&(sp->s.x)

       movl   %eax, 12(%eax) // sp->next= sp

       popl   %ebp

       ret