云顶娱乐官方入口-www.40081.com-云顶娱乐网址4118112
做最好的网站
您的位置:云顶娱乐官方入口 > 云顶娱乐网址4118112 > 预备知识2,1、.globl表示汇编器不能在汇编之后就

预备知识2,1、.globl表示汇编器不能在汇编之后就

2019-12-03 01:33

一个最基本的汇编程序如下所示:

程序的指令级表示(汇编)

预备知识1:

堆栈:先进后出,操作有push(),pop(),peek()

应用:函数调用 树的遍历(所有递归操作) 表达式的计算

 

预备知识2:

寄存器:CPU中临时存储数据的空间 小 快 贵

32位(0~31)EAX  以前8086是16位(0~15)AH,AL

通用寄存器 AX,BX,CX,DX:进行运算处理等 *函数调用的规则

寄存器ESI和EDI source和destination:copy数据

***EBP:描述了一个栈帧(一个栈内元素),永远指向一个栈帧的开始处 指向当前栈帧

***ESP:整个函数堆栈的栈顶,永远指向一个栈的栈顶

 

预备知识3:

汇编:GCC编译器(参见《深入理解计算机》)

MOVL $0x3051,%EAX 把0x3051这个值放到EAX寄存器,4个字节

MOVL %EAX,-12(%EBP) 把寄存器EAX的值,存放到EBP指向的地址减去12个字节的地方

LEAL -12(%EBP) %EAX 把%EBP减去12得到的地址,放到EAX寄存器当中

PUSHL %EBP 把寄存器EBP的值压栈

POPL %EBP 把栈顶的值弹出,存放到EBP寄存器中

SUBL %4 %ESP 把ESP寄存器的值减去4

 

 

预备知识4:

指针:内存地址 (参见《C与指针》)

指针的指针

类比java的引用

 

预备知识5:

C语言

(1)内存两种分配方式:

·静态分配:栈 编译器完成(编译时) 栈从上往下生长

·动态分配:堆 编译时无法确定运行时 堆从下往上生长

 

 

(2)函数帧

每个函数有个栈帧,栈帧大小不确定,因为要记录函数内部的信息,根据信息多少而定。

举例 函数A调用B,B调用C,C调用D,则栈中A到D地址逐渐减小(虚拟地址就是这样设计栈的)可能溢出

 

栈在内存中,EBP和ESP在寄存器(CPU中)

*EBP和ESP的工作原理

 

调用push操作,ESP值自动减4(减去4个字节)

调用pop操作,ESP值自动加4(减去4个字节)

(一定要注意栈从上往下生长,所以一个栈帧的开始处在高地址)

因为EBP和ESP只有一个,所以对他们的push和pop操作更多,用来记住其值。

 

机器级没有变量名!没有变量名的存储了!

 

例子:

int demo(){

         int x=10;

         int y=20;

         int sum=add(&x,&y);

         printf(“the sum is %dn”,sum);

return sum;

}

int add(*xp,*yp)

{

         int x =*xp;

         int y=*yp;

return x+y;

}

 

转换成汇编语言(Intel中的)(自己应该动手写一下,顺便把栈和指针标出来)

 

Demo

1           pushl  %ebp

2           movl  %esp  %ebp

3           subl  %24  esp

4           movl  $10  -4(%ebp)

5           movl  $20  -8(%ebp)

6           leal  -8(%ebp)  %eax

7           movl  %eax  4(%esp)

8           leal  -4(%ebp)  %eax

9           movl  %eax  esp

10       call add

11       打印结果

 

add:

  1. pushl  %ebp
  2. movl  %esp  %ebp
  3. pushl  %ebx
  4. movl  8(%ebp)  %edx
  5. movl  12(%ebp)  %ecx
  6. movl  (%edx)  %ebx
  7. movl  (%ecx)  %eax
  8. add    %ebx  %eax
  9. popl  %ebx
  10. popl  %ebp
  11. ret

Ps:ret是return语句,当add将最后结果算出,add函数帧弹栈以后,暴露出的内存地址里写的是主函数留下的打印指令的地址。

.section .data

.section .text
.globl _start
_start:
        movl $1, %eax   # the number 1 is the number of the exit system call

        movl $0, %ebx

        int $0x80

 

1、.globl表示汇编器不能在汇编之后就丢弃该标识,因为接下来的连接器还会使用它。_start是一个特殊的标识,它必须用.globl修饰,因为它代表了程序开始的入口

否则在链接的时候会报“ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078”的错误

 

2、几个通用寄存器如下所示:(但事实上,对每个通用寄存器,都至少在一条指令中它们是用于特殊用途的)

  • %eax
  • %ebx
  • %ecx
  • %edx
  • %edi
  • %esi

另外几个用于特殊目的的寄存器如下所示:

  • %ebp
  • %esp
  • %eip
  • %eflags

 

3、在每次系统调用过程中,%eax总是用于存放系统调用的编号,而对于其他寄存器,在不同的系统调用中有不同的用途。例如在上述例子中,%ebx就用于存储返回值

 

4、"int $0x80"中的int代表interrupt,而interrupt表示中断当前正常的程序执行流,并且将控制权转交给内核,让它能执行系统调用

 

5、几种寻址模型:

  • direct addressing mode:
    • movl ADDRESS, %eax  ----- 将地址ADDRESS中的内容放到%eax中
  • indexed addressing mode:
    • movl string_start(, %ecx, 1), %eax ---- 将地址string_start + %ecx * 1地址中的内容放到%eax中
  • indirect addressing mode:
    • movl (%eax), %ebx ----- 将地址%eax中的内容放到%ebx中
  • base pointer addressing mode:
    • movl 4(%eax), %ebx ----- 将地址%eax + 4中的内容放到%ebx中
  • immediate mode:
    • movl $12, %eax ----- 将立即数12放到%eax中,若没有$符号,则意为将地址12中的值放到%eax内

 

6、汇编函数调用规则

在调用一个函数之前,首先将所有参数以相反的声明顺序入栈,之后再调用call指令

call主要做两件事:1、它将下一条指令的地址入栈 2、将%eip设置为函数的初始地址、

接着进入函数内部,首先要做的就是将%ebp入栈,并将当前%esp的值赋值给%ebp。事实上,我们就是利用%ebp作为基准来获取函数的参数和局部变量

Parameter #N <--- N*4+4(%ebp)
...
Parameter 2 <--- 12(%ebp)
Parameter 1 <--- 8(%ebp)
Return Address <--- 4(%ebp)
Old %ebp <--- (%esp) and (%ebp)

最后在函数返回时,应该让%ebp恢复到上一个函数的状态,并调用ret返回,ret的作用是将上图的Return Address装入%eip中,恢复上一个函数的执行。具体的指令如下:

movl %ebp, %esp

popl %ebp

ret

 

7、mov指令不能用于内存和内存之间或者段寄存器和段寄存器之间的数据转移。不过其实内存和内存之间的数据转移是可以的,通过字符串的转移指令movs

 

8、pusha将8个通用寄存器入栈,入栈的顺序为:eax, ecx, edx, ebx, esp, ebp, esi, edi

 

9、inc/dec指令并不影响CF标志位

 

10、cr0中包含了系统控制的flag,包括标志位PE置位,则系统处于保护模式,标志位PG置位,则处理器利用页表将线性地址转换为物理地址

cr2用于保存导致缺页异常的线性地址,cr3用于保存页目录的地址

 

本文由云顶娱乐官方入口发布于云顶娱乐网址4118112,转载请注明出处:预备知识2,1、.globl表示汇编器不能在汇编之后就

关键词:

  • 上一篇:没有了
  • 下一篇:没有了