汇编push,pop,call操作

博客围绕汇编程序展开,原程序因地址操作产生随机字符,经修改语句后仍出现段错误,将字符定义放到数据段可解决。还介绍了用ALD调试器查看寄存器值,同时指出CALL和RET有压栈出栈操作,不用数据段时程序运行过程更清晰。

[section .text]
global _start
                     charact  db  'a'
_start:
    MOV ECX,charact               
    PUSH ECX                          
    CALL usestack                   
    POP ECX                             
    MOV EDX,1
   MOV EBX,1
   MOV EAX,4
    INT 0X80
   MOV EAX,1
   MOV EBX,0
   INT 0X80
 usestack:
   MOV EBP, ESP                   
    PUSHAD                             
    INC  word[EBP+4]  
    POPAD
   RET  
这个程序会得到随机字符,因为EBP中放的是charact的地址,INC  word[EBP+4],这里把地址加1,得到未知地址,所以有随机字符产生。改为以下2条语句,这个问题解决:MOV EBP,DWORD[EBP+4] ;得到charact的地址,存入EBP
    INC WORD[EBP]        ;对charact的值加1
这样改了以后,通过ald调试,可以看到执行过程中各个寄存器的值是对的,但是,程序不能执行,会提示段错误。这时可以将charact的定义放到数据段.data中,来解决这个问题。所以,最后的程序是这样的:
[section .data]
                     charact  db  'a'                 ;这里,'a'的地址是0X80490B8
[section .text]
global _start
_start:
    MOV ECX,charact                                ;ESP=0XBFFFE040      EBP=0                               ECX=0X80490B8
    PUSH ECX                                           ;ESP=0XBFFFE03C      EBP=0                               ECX=0X80490B8
    CALL usestack                                    ;ESP=0XBFFFE038      EBP=0                              ECX=0X80490B8
    POP ECX                                              ;ESP=0XBFFFE040      EBP=0XBFFFE038        ECX=0X80490B8
    MOV EDX,1
   MOV EBX,1
   MOV EAX,4
    INT 0X80
   MOV EAX,1
   MOV EBX,0
   INT 0X80
 usestack:
   MOV EBP, ESP                                   ;ESP=0XBFFFE038      EBP=0XBFFFE038        ECX=0X80490B8
    PUSHAD                                             ;ESP=0XBFFFE018      EBP=0XBFFFE038        ECX=0X80490B8
    MOV EBP,DWORD[EBP+4]             ;ESP=0XBFFFE018      EBP=0X80490B8         ECX=0X80490B8
    INC  WORD[EBP]                              ;ESP=0XBFFFE018      EBP=0X80490B8         ECX=0X80490B8
    POPAD                                                ;ESP=0XBFFFE038      EBP=0XBFFFE038         ECX=0X80490B8
   RET                                                       ;ESP=0XBFFFE03C      EBP=0XBFFFE038         ECX=0X80490B8

后面的寄存器内容是用ALD(Assembly Language Debugger)调试得到的。ALD是一款LINUX下的调试器。

这里要注意的是,CALL和RET的时候也有压栈出栈操作。

如果不用数据段,而直接用命令:MOV ECX,charact,则程序运行过程会看得更清楚,特别是INC  WORD[EBP] 这句话。因为传递的是值而不是地址,加1的操作看得会更清楚。


### 数据操作相关指令的解释 在编程中,尤其是汇编语言和低级语言中,数据操作指令是非常基础且重要的。以下是 `move`、`push`、`add`、`call` 和 `pop` 指令的详细说明: #### 1. **Move 指令** `Move` 指令用于将数据从一个置复制到另一个置。尽管名称为“移动”,但实际上大多数实现是进行数据的复制,而不会清除源数据[^1]。 ```assembly mov eax, ebx ; 将 ebx 的值复制到 eax ``` #### 2. **Push 指令** `Push` 指令用于将数据压入栈中。栈是一个后进先出(LIFO)的数据结构,通常用于保存临时数据或函数调用时的参数[^2]。 ```assembly push eax ; 将 eax 的值压入栈中 ``` #### 3. **Add 指令** `Add` 指令用于执行加法运算,并将结果存储到目标寄存器或内存置中。它是算术运算中最常用的指令之一[^1]。 ```assembly add eax, ebx ; 将 eax 和 ebx 相加,结果存储在 eax 中 ``` #### 4. **Call 指令** `Call` 指令用于调用子程序或函数。它会将当前指令的地址压入栈中,以便在子程序结束后能够返回到正确的代码置[^3]。 ```assembly call my_function ; 调用名为 my_function 的子程序 ``` #### 5. **Pop 指令** `Pop` 指令用于从栈中弹出数据,并将其存储到指定的寄存器或内存置中。与 `push` 指令配合使用,可以恢复之前保存的数据[^2]。 ```assembly pop eax ; 从栈中弹出数据并存储到 eax 中 ``` ### 示例代码 以下是一个简单的汇编代码示例,展示了这些指令的组合使用: ```assembly section .data num1 dd 10 num2 dd 20 section .text global _start _start: mov eax, [num1] ; 将 num1 的值加载到 eax add eax, [num2] ; 将 num2 的值加到 eax push eax ; 将 eax 的值压入栈中 call print_result ; 调用打印结果的子程序 pop ebx ; 从栈中弹出结果到 ebx print_result: ret ; 返回到调用处 ``` ### 注意事项 - 在实际编程中,确保栈的正确管理以避免溢出或数据丢失。 - 使用 `call` 和 `ret` 指令时,必须保证栈的完整性,否则可能导致程序崩溃。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值