开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 111|回复: 6
收起左侧

[易语言] 寄存器保护问题

[复制链接]
结帖率:80% (8/10)
发表于 昨天 22:12 | 显示全部楼层 |阅读模式   江苏省常州市
15精币
继续学习汇编。
deepseek说按照“IA-32 ABI 标准”,被调用的函数应该是在执行前保存EBX、ESI、EDI(EBP就不说了)等寄存器的数据,看到有些子程序汇编版,几百字节汇编代码也没说刻意去保存这几种寄存器(它根本不知道上层函数没有在使用这些寄存器)。我可以理解为这种标准有点过时了吗?针对c这种底层/基础的语言来说规范太重要了,但是易语言是典型的牺牲效率来提升简便和健壮性,汇编中做的检查太多了,大部分环境下不用考虑再保存这些寄存器呢?


回答提醒:如果本帖被关闭无法回复,您有更好的答案帮助楼主解决,请发表至 源码区 可获得加分喔。
友情提醒:本版被采纳的主题可在 申请荣誉值 页面申请荣誉值,获得 1点 荣誉值,荣誉值可兑换荣誉会员、终身vip用户组。
快捷通道:申请荣誉值
结帖率:100% (2/2)

签到天数: 3 天

发表于 昨天 22:30 | 显示全部楼层   四川省成都市
你想弄清楚 IA-32 ABI 中关于寄存器保存的规范是否已经过时,同时对比了 C 语言对规范的严格性和易语言/汇编中似乎可以“省略”这些保存操作的现象,核心是想理解这个规范的实际价值和适用场景。### 一、先澄清:IA-32 ABI 寄存器保存规则从未“过时”,而是有明确的设计目的首先要明确,IA-32 ABI(System V AMD64 ABI 的 32 位版本)中对寄存器的“调用者保存(caller-saved)”和“被调用者保存(callee-saved)”划分,**不是可有可无的“规范”,而是保证程序内存安全、函数调用栈可预测的核心规则**。#### 1. 先明确寄存器的分类(IA-32 核心规则)| 寄存器类型       | 包含的寄存器       | 责任方       | 规则说明                                                                 ||------------------|--------------------|--------------|--------------------------------------------------------------------------|| 被调用者保存     | EBX、ESI、EDI、EBP | 被调用函数   | 被调用函数如果要修改这些寄存器,必须先保存(入栈),函数返回前恢复       || 调用者保存       | EAX、ECX、EDX      | 调用函数     | 调用函数如果需要保留这些寄存器的值,必须在调用其他函数前自己保存           |#### 2. 为什么你会看到“没保存”的汇编代码?你看到的“几百字节汇编代码没刻意保存 EBX/ESI/EDI”,**不是规范过时,而是这些代码满足了以下条件之一**:- 条件1:该汇编子程序**根本没有修改**这些寄存器(只读不写),自然不需要保存;- 条件2:该汇编子程序是“私有”的(仅被特定代码调用),且调用方明确知道“这个子程序会修改这些寄存器”,调用方提前做了保存;- 条件3:该代码运行在“单上下文环境”(如裸机、简单内核),没有多函数嵌套调用,不会出现寄存器值被覆盖的问题;- 条件4:编译器/手写汇编做了“优化”——如果能证明这些寄存器的值后续不会被使用,就省略保存/恢复操作。#### 3. 易语言“检查多、牺牲效率”的本质易语言看似“汇编中做的检查太多”,本质是:- 易语言的运行时为了“简便和健壮性”,默认对所有寄存器做了“过度保护”(不管是否需要修改,都保存/恢复);- 这种做法牺牲了少量效率,但避免了新手手写汇编时违反 ABI 导致的崩溃(比如上层函数的 EBX 值被下层函数覆盖);- 这不是“规范没用”,而是易语言用“冗余操作”掩盖了规范的细节,让使用者不用关心底层规则。#### 4. “大部分环境下不用考虑保存”的误区只有满足以下“极端场景”,才可以不遵守寄存器保存规则:- 场景1:程序是纯汇编编写的单函数,无任何函数调用;- 场景2:程序运行在完全可控的环境(如专用嵌入式固件),且所有代码由你手写,能全程追踪寄存器的使用;- 场景3:一次性执行的临时代码(如调试脚本),执行后直接退出,无需保留上下文。一旦涉及“C 代码调用汇编子程序”“多函数嵌套调用”“动态链接库”,违反 ABI 规则会直接导致崩溃:```c// 示例:C 调用违反 ABI 的汇编子程序导致崩溃#include <stdio.h>// 汇编子程序(伪代码):修改 EBX 但未保存__asm__ (    "my_func:\n"    "mov ebx, 0x12345678\n"  // 修改 EBX 但未保存    "ret\n");int main() {    int val = 0x87654321;    __asm__ ("mov ebx, %0" : : "r"(val));  // 给 EBX 赋值    my_func();  // 调用汇编函数,修改 EBX    // 此时 EBX 被覆盖,后续使用 EBX 会得到错误值,甚至崩溃    int res;    __asm__ ("mov %0, ebx" : "=r"(res));    printf("EBX value: 0x%x\n", res);  // 输出 0x12345678,而非预期的 0x87654321    return 0;}```### 二、C 语言为什么对 ABI 规范“极其严格”?C 作为底层语言,其跨平台、可链接、可复用的核心依赖于 ABI 规范:1. **编译器协作的基础**:不同编译器(GCC、Clang、MSVC)生成的代码能互相链接,正是因为都遵守同一套 ABI;2. **函数调用的可预测性**:C 函数的嵌套调用、递归、动态调用(如 `dlopen`),都依赖寄存器/栈的状态可预测;3. **调试和维护的可行性**:遵守 ABI 的代码,调试时能准确回溯函数调用栈,寄存器的值符合预期。如果 C 语言不遵守 ABI,会出现:- 静态库/动态库链接失败;- 函数返回值错误、栈溢出;- 调试器无法正确显示变量值;- 多线程/多进程环境下上下文混乱。### 总结1. **IA-32 ABI 寄存器保存规则从未过时**:它是多函数调用、跨编译器协作的基础,只是在“极简场景”下可以省略(而非规则失效);2. **易语言的“冗余检查”是对新手的保护**:不是规范没用,而是用效率换易用性,避免新手违反 ABI 导致崩溃;3. **C 语言必须严格遵守 ABI**:底层语言的“灵活性”建立在规范之上,违反规则会直接导致程序不可控、崩溃。简单来说:规范的存在是为了“通用场景下的可靠性”,而你看到的“省略保存”是“特定场景下的优化”,二者不冲突,也不存在“规范过时”的说法。


补充内容 (2026-3-3 22:30):
来自豆包
回复

使用道具 举报

结帖率:80% (4/5)

签到天数: 4 天

发表于 昨天 22:40 高大上手机用户 | 显示全部楼层   广西壮族自治区柳州市
ebx ecx edi esi 在使用到的情况下是需要保存的吧,32位易失寄存器只有eax edx 这俩不需要保存
回复

使用道具 举报

结帖率:100% (1/1)

签到天数: 3 天

发表于 昨天 22:44 | 显示全部楼层   江西省南昌市
ABI规范没有过时。它是确保软件(尤其是C/C++/Rust等系统语言生态)中不同组件能够大规模、可靠协作的基础工程设施,其价值在大型、复杂系统中无可替代。

汇编代码不保存寄存器是特定场景的优化。这通常发生在性能极端敏感的热点路径,或者完全可控的内部函数中。这是一种“知其然且知其所以然”的手动优化,但不应作为通用实践,因为它破坏了代码的模块性和可复用性。

易语言的策略是另一种选择。它用运行时检查换取开发简便和健壮性,面向的是不同的开发群体和问题域。它的“繁重”在于运行时安全,而ABI的“繁重”在于二进制合约的稳定性,两者目标不同。



回复

使用道具 举报

结帖率:100% (53/53)

签到天数: 4 天

发表于 昨天 22:55 | 显示全部楼层   福建省宁德市
看调用约定了__stdcall
被调用者 负责保存恢复:ebx、esi、edi、ebp、esp
调用者 负责eax、ecx、edx

易语言里你要用ebx、esi、edi肯定要push、pop
push、pop寄存器速度很快的,1个周期左右
大量循环、算法的时候才精打细算
回复

使用道具 举报

结帖率:100% (3/3)

签到天数: 4 天

发表于 8 小时前 | 显示全部楼层   重庆市重庆市
EAX, ECX, EDX 是“易失性寄存器”(你可以随便用,不用管恢复,EAX 还要用来做返回值),但 EBX, ESI, EDI, EBP 是“非易失性寄存器”,必须遵守寄存器保护规则
回复

使用道具 举报

结帖率:80% (8/10)

签到天数: 4 天

 楼主| 发表于 25 分钟前 | 显示全部楼层   江苏省常州市
易语言中,用“&子程序1”后,会生成“代理函数”,汇编代码如下:
=====
push esi
push edi
push ebx
call 子程序1真实地址
pop ebx
pop edi
pop esi
ret
=====
这似乎就已经提前保护了这几种寄存器,说明易在内部编译后会有保护代码,至于子程序1后面的自己业务代码部分猜测不用再保存了。而且ebx寄存器在局部变量回收内存时会被频繁赋值使用(编译自动生成的汇编),也没见它有保存过

补充内容 (2026-3-4 09:14):
主线程的“消息事件”处理函数中也是提前保护了
=====
push ebp
mov ebp, esp
sub esp, 0x18
push ebx
push esi
push edi
......
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
retn 0x04
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备2025452707号) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表