ret,retf,iret的区别

本文介绍了计算机CPU指令集中关于过程调用返回的几种指令,包括ret、retf和iret的功能和使用场景。ret用于段内返回,retf用于段间返回,而iret则专门用于从硬件或软件中断中返回。

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

ret

RET, and its exact synonym RETN, pop IP or EIP from the stack and transfer control to the new address. Optionally, if a numeric second operand is provided, they increment the stack pointer by a further imm16 bytes after popping the return address.

ret:也可以叫做近返回,即段内返回。处理器从堆栈中弹出IP或者EIP,然后根据当前的CS:IP跳转到新的执行地址。如果之前压栈的还有其余的参数,则这些参数也会被弹出。

retf

RETF executes a far return: after popping IP/EIP, it then pops CS, and then increments the stack pointer by the optional argument if present.

retf:也叫远返回,从一个段返回到另一个段。先弹出堆栈中的IP/EIP,然后弹出CS,有之前压栈的参数也会弹出。(近跳转与远跳转的区别就在于CS是否压栈。)

iret

IRET returns from an interrupt (hardware or software) by means of popping IP (or EIP), CS and the flags off the stack and then continuing execution from the new CS:IP.

iret:用于从中断返回,会弹出IP/EIP,然后CS,以及一些标志。然后从CS:IP执行。

来源:https://linux.cn/blog-11720-5748.html

; 系统端口定义 PORT_8259_OCW EQU 2000H ; 8259A命令端口 PORT_8259_OCW2 EQU 2002H ; 8259A数据端口 PORT_8253_CTL EQU 4006H ; 8253控制寄存器 PORT_8253_1 EQU 4002H ; 8253计数器1 PORT_8255_A EQU 6000H ; 8255端口A PORT_8255_B EQU 6002H ; 8255端口B PORT_8255_C EQU 6004H ; 8255端口C PORT_8255_CTL EQU 6006H ; 8255控制寄存器 ; 数据段 DATA SEGMENT SECONDS DB 0 ; 当前秒数(0-59) RUN_FLAG DB 0 ; 运行标志(0=暂停,1=运行) COUNT_10MS DB 0 ; 10ms计数器(100次=1秒) DISP_BUFFER DB 2 DUP(0) ; 显示缓冲区[十位, 个位] ; 共阴数码管段码表 (0-9, 带小数点关闭) SEG_CODES DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH ; 按键状态标志 KEY_START_PRESSED DB 0 KEY_PAUSE_PRESSED DB 0 KEY_RESET_PRESSED DB 0 DATA ENDS ; 代码段 CODE SEGMENT ASSUME CS:CODE, DS:DATA ; ============== 复位入口点 ============== ORG 0FFFF0H JMP FAR PTR START ; 跳转到主程序 ; ============== 主程序 ============== START: CLI ; 关中断 MOV AX, DATA MOV DS, AX ; 初始化变量 MOV SECONDS, 0 MOV RUN_FLAG, 0 MOV COUNT_10MS, 0 MOV KEY_START_PRESSED, 0 MOV KEY_PAUSE_PRESSED, 0 MOV KEY_RESET_PRESSED, 0 ; 初始化硬件 CALL INIT_8255 CALL INIT_8253 CALL INIT_8259 ; 设置中断向量(IR0对应中断类型08H) MOV AX, 0 MOV ES, AX MOV DI, 08H*4 ; 中断向量地址 = 08H * 4 MOV AX, OFFSET TIMER_ISR MOV ES:[DI], AX ; 设置IP MOV AX, CS MOV ES:[DI+2], AX ; 设置CS ; 初始显示 CALL UPDATE_DISPLAY STI ; 开中断 ; 主循环 MAIN_LOOP: CALL DISPLAY ; 刷新显示 CALL CHECK_KEYS ; 检测按键 JMP MAIN_LOOP ; ============== 初始化8255 ============== INIT_8255 PROC MOV AL, 10000001B ; 控制字: PA/PB输出, PC输入 OUT PORT_8255_CTL, AL MOV AL, 0FFH ; 关闭数码管显示 OUT PORT_8255_A, AL MOV AL, 00H OUT PORT_8255_B, AL RET INIT_8255 ENDP ; ============== 初始化8253 ============== INIT_8253 PROC ; 计数器1: 方式3, 二进制, 先低后高 MOV AL, 01110110B OUT PORT_8253_CTL, AL ; 写入计数值10000 (0x2710) -> 1MHz/10000=100Hz MOV AL, 10H ; 低字节 OUT PORT_8253_1, AL MOV AL, 27H ; 高字节 OUT PORT_8253_1, AL RET INIT_8253 ENDP ; ============== 初始化8259A ============== INIT_8259 PROC ; ICW1: 边沿触发, 单片, 需要ICW4 MOV AL, 00010011B OUT PORT_8259_OCW, AL ; ICW2: 中断向量基址08H MOV AL, 08H OUT PORT_8259_OCW2, AL ; ICW4: 8086模式, 非缓冲, 全嵌套 MOV AL, 00000001B OUT PORT_8259_OCW2, AL ; OCW1: 开启IR0中断 MOV AL, 11111110B OUT PORT_8259_OCW2, AL RET INIT_8259 ENDP ; ============== 定时中断服务程序 ============== TIMER_ISR PROC FAR PUSH AX PUSH BX PUSH DS MOV AX, DATA MOV DS, AX ; 更新10ms计数器 INC COUNT_10MS CMP COUNT_10MS, 100 ; 100次中断=1秒 JB END_ISR ; 重置计数器 MOV COUNT_10MS, 0 ; 检查运行标志 CMP RUN_FLAG, 1 JNE END_ISR ; 秒计数器递增 INC SECONDS CMP SECONDS, 60 JB UPDATE_DISP MOV SECONDS, 0 ; 满60秒归零 UPDATE_DISP: CALL UPDATE_DISPLAY END_ISR: ; 发送EOI命令 MOV AL, 20H OUT PORT_8259_OCW, AL POP DS POP BX POP AX IRET TIMER_ISR ENDP ; ============== 更新显示缓冲区 ============== UPDATE_DISPLAY PROC MOV AL, SECONDS MOV AH, 0 MOV BL, 10 DIV BL ; AL=十位, AH=个位 ; 十位段码 LEA BX, SEG_CODES XLAT ; AL = SEG_CODES[AL] MOV DISP_BUFFER, AL ; 个位段码 MOV AL, AH XLAT ; AL = SEG_CODES[AL] MOV DISP_BUFFER+1, AL RET UPDATE_DISPLAY ENDP ; ============== 数码管显示 ============== DISPLAY PROC ; 关闭所有位选 MOV AL, 00H OUT PORT_8255_B, AL ; 显示十位 MOV AL, DISP_BUFFER OUT PORT_8255_A, AL MOV AL, 01H ; PB0=1(选中十位) OUT PORT_8255_B, AL CALL DELAY_500US ; 关闭所有位选 MOV AL, 00H OUT PORT_8255_B, AL ; 显示个位 MOV AL, DISP_BUFFER+1 OUT PORT_8255_A, AL MOV AL, 02H ; PB1=1(选中个位) OUT PORT_8255_B, AL CALL DELAY_500US RET DISPLAY ENDP ; ============== 短延时(500μs) ============== DELAY_500US PROC PUSH CX MOV CX, 150 DL1: LOOP DL1 POP CX RET DELAY_500US ENDP ; ============== 按键检测 ============== CHECK_KEYS PROC ; 读取PC口状态 IN AL, PORT_8255_C AND AL, 07H ; 只取低3位(PC0-PC2) NOT AL ; 反转(0=按下) AND AL, 07H ; 保留低3位 ; 检测开始键(PC0) TEST AL, 01H JZ START_NOT_PRESSED ; 按键按下 CMP KEY_START_PRESSED, 0 JNE START_ALREADY_PRESSED MOV KEY_START_PRESSED, 1 MOV RUN_FLAG, 1 ; 开始运行 JMP START_HANDLED START_NOT_PRESSED: MOV KEY_START_PRESSED, 0 START_ALREADY_PRESSED: START_HANDLED: ; 检测暂停键(PC1) TEST AL, 02H JZ PAUSE_NOT_PRESSED CMP KEY_PAUSE_PRESSED, 0 JNE PAUSE_ALREADY_PRESSED MOV KEY_PAUSE_PRESSED, 1 MOV RUN_FLAG, 0 ; 暂停 JMP PAUSE_HANDLED PAUSE_NOT_PRESSED: MOV KEY_PAUSE_PRESSED, 0 PAUSE_ALREADY_PRESSED: PAUSE_HANDLED: ; 检测复位键(PC2) TEST AL, 04H JZ RESET_NOT_PRESSED CMP KEY_RESET_PRESSED, 0 JNE RESET_ALREADY_PRESSED MOV KEY_RESET_PRESSED, 1 MOV SECONDS, 0 ; 复位秒数 MOV RUN_FLAG, 0 ; 停止运行 CALL UPDATE_DISPLAY JMP RESET_HANDLED RESET_NOT_PRESSED: MOV KEY_RESET_PRESSED, 0 RESET_ALREADY_PRESSED: RESET_HANDLED: RET CHECK_KEYS ENDP ; ============== 20ms延时(按键消抖) ============== DELAY_20MS PROC PUSH CX MOV CX, 6000 DL2: LOOP DL2 POP CX RET DELAY_20MS ENDP CODE ENDS END START 上述汇编代码基于8086汇编语言设计了一个硬件系统,用于60s循环计时,使用了8259A,8255,8253,74ls373,74ls138,但是在代码编写部分出了错误,比如出现了段超过64k和一些无效指令操作,请你修改这段汇编代码,并尽量减少造成的硬件连接的变化。
最新发布
07-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值