c++ - 在 Turbo C++ 内联汇编中使用 32 位寄存器,如 EAX
问题描述
我用 Turbo C++ 写了一个宏
部分 C++ 程序(仅限宏)
/* @intvar address=0x8f79fff4 */
{
-asm mov cx,08f7h
_asm mov es,cx
-asm mov ax,9000h
-asm mov ds,ax
-asm mov ax,0fff4h
-asm mov si,ax
/* -asm mov cl,0fh */
-asm mov eax,es
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm add eax,ds[si]
-asm mov ah,9h
-asm mov al,[eax]
-asm mov bh,0h
-asm mov bl,0h
-asm mov cx,0h
-asm int 10h
}
该行
-asm mov cl,0fh
导致语法错误。- 因此我使用
16 off -asm shl,eax,1
.
- 因此我使用
该行
-asm mov eax,es
导致错误“无法识别eax”使用 32 位寄存器的 TASM 指令 .386P
eax
不起作用
为什么我不能写0fh
注册cl
?
解决方案
我从来没有使用过_asm
nor -asm
(我认为-asm
无效),而是使用这个:
asm{
// multi line
// assembly code
// in here
};
这在旧的 turbo C++ 和 Pascal 中也可以正常工作......所以只需摆脱所有的-asm
and ,只需在 asm 代码的开头和结尾_asm
放置 single 即可。asm{
}
但是你的代码有很多语法错误!!!
例如到底是什么:
shl,eax,1
它应该是:
shl eax,1
或者更好的是,您可以使用shl eax,16
指令。立即移位是 186 中的新功能,使用 32 位寄存器的代码只能在 386 或更高版本上运行。或者使用 2x 16bitpush
和 1x 32-bitpop
移动es
到更高的 16 位eax
,作为将两个 16 位事物连接到 32 位寄存器中的一种方法。(不过,在现代 CPU 上相当慢。)
另一个问题是 Turbo C++ 编译器无法生成带有 32 位寄存器的代码,即使是在 16 位模式下(至少是我的)。 因此,您确实需要使用不同的编译器才能使所有这些成为可能。
在项目选项中,您可以检查 x386 和 x387 指令集,但这不适用于内联汇编...带有 32 位寄存器的行会抛出错误(未知eax
或类似的东西)所以您需要重写代码以使用 16位寄存器。
另一个问题是您使用了错误的十六进制数字格式。
在 C/C++ 中,您需要使用0x0
前缀而不是h
后缀。所以例如9000h
应该是0x09000
!!!
另一个可能的问题是解决您使用
add eax,ds[si]
您在此处使用 16 位指针,但稍后使用 32 位[eax]
指针。你确定那是你想要的吗?此外,您真的想要进行 32 位加载,而不是仅仅将新的低 16 位合并到 EAX 中mov ax, [si]
吗?不同之处在于加法的进位是否传播到高位,或者该内存位置的双字的上半部分是否非零。
此外,DS 是默认段(BP 或 ESP 除外),那么为什么在此处明确指定 DS 而不是在 中[eax]
?您无法避免使用 32 位偏移量的 DS 基数。格式也是这样的:
add ax,[ds:si]
或者:
add eax,dword[ds:si]
取决于你想做什么。编译器(TASM,NASM,...)之间的寻址格式不同asm
,这很麻烦。
此外,在您尝试将 EAX 作为指针取消引用之前asm mov ah,9
,修改 EAX 的第二个字节。如果您在 EAX中构造一个有效的偏移量(即地址的低位部分),那么以其他顺序执行这两条指令可能是有意义的。mov al,[eax]
seg:off
最后但并非最不重要的一点是,您不保留注册值,这简直是个坏主意。与 MSVC 不同,在 MSVC 中,编译器会确定您的 asm 使用哪些寄存器并为您保存/恢复它们,您push/pop
必须在 asm 代码的开始/结束处添加语句,否则您可能会损坏 C/C++ 编译器生成的寄存器值您周围的代码块取决于。
并非所有寄存器都需要保留(除非您编写 ISR 代码),但应恢复段和索引寄存器。IIRC ax 保存 asm 函数的返回值(不确定是否也在 TC 中)。
(在 MSVC 中,您可以在 EAX 中保留一个值,然后让执行从非 void 函数的末尾(没有 a return
),并且该函数的返回值是您在 EAX 中留下的值。当内联函数包含一个时,MSVC 实际上支持这一点asm{}
块,但如果这在 TC 中有效,则可能只是在 asm 块之后不内联并且不弄乱 AX。)
也看看这个:
在第一个项目符号中,有使用 asm 的 TC++ 示例...
这是我刚刚在我的 TC 档案中找到的另一个示例(使用 x387):
long sin(float a,long b)
{
long alfa=long(a*1000);
long far* ptr=(long far*)0xA000FA00;
ptr[0]=alfa;
ptr[1]=1000;
ptr[2]=b;
asm {
fninit
push es
push di
mov di,0xA000
mov es,di
mov di,0xFA00
fild dword[es:di]
fild dword[es:di+4]
fdivp st(1),st(0)
db 0xD9,0xFE
fild dword[es:di+8]
fmulp st(1),st(0);
fistp dword[es:di]
pop di
pop es
}
b=ptr[0];
return b;
}
我从中推断出 TC 的寻址语法/格式,因为我根本不记得了。
推荐阅读
- reactjs - 用 formik 转义方括号
- c# - 拆分字符串并转换为可为空的 long
- r - 具有不同列数的制表符分隔文件 - R
- sinch - 如何在 sinch PSTN JS-SDK 中使用网络到电话接听来电
- jsqlparser - JSQL Parser - 关于 dblink 的信息
- c# - 如何统一从子类更改父类变量
- alfresco - Alfresco:搜索所有没有父节点的节点
- jquery - jquery:不选择不排除预期元素
- java - 使用大量行时出现 RowsExceededException
- c - 预快速警告:“算术溢出:32 位值被移位,然后转换为 64 位值。”