使用 AT&T 内联汇编器 for GCC
Using AT&T inline assembler for GCC
我正在编写一个简单但有点具体的程序:
目的:根据它的阶乘
计算数字 要求:所有计算必须在gcc内联asm(at&t语法)上完成
源代码:
#include <iostream>
int main()
{
unsigned n = 0, f = 0;
std::cin >> n;
asm
(
"mov %0, %%eax n"
"mov %%eax, %%ecx n"
"mov 1, %%ebx n"
"mov 1, %%eax n"
"jmp cycle_startn"
"cycle:n"
"inc %%ebxn"
"mul %%ebxn"
"cycle_start:n"
"cmp %%ecx, %%eaxn"
"jnz cyclen"
"mov %%ebx, %1 n":
"=r" (n):
"r" (f)
);
std::cout << f;
return 0;
}
此代码会导致 SIGSEV。
英特尔 asm 语法 (http://pastebin.com/2EqJmGAV) 上的相同程序工作正常。为什么我的"AT&T计划"失败了,我该如何解决?
#include <iostream>
int main()
{
unsigned n = 0, f = 0;
std::cin >> n;
__asm
{
mov eax, n
mov ecx, eax
mov eax, 1
mov ebx, 1
jmp cycle_start
cycle:
inc ebx
mul ebx
cycle_start:
cmp eax, ecx
jnz cycle
mov f, ebx
};
std::cout << f;
return 0;
}
UPD:推送到堆栈并恢复已使用的寄存器会得到相同的结果:SIGSEV
你的输入和输出方式错误。
所以,从改变开始
"=r" (n):
"r" (f)
自:
"=r" (f) :
"r" (n)
然后我怀疑你会想告诉编译器关于 clobbers(你正在使用的寄存器不是输入或输出):
所以添加:
: "eax", "ebx", "ecx"
在上面的两行之后。
我个人会做一些其他的改变:
- 使用本地标签(
1:
和2:
等),这允许在没有"重复标签"的情况下复制代码。 - 使用
%1
而不是%%ebx
- 这样,您就不会使用额外的寄存器。 - 将
%0
直接移至%%ecx
。您稍后将1
加载到%%eax
两个指令中,那么它在%%eax
中有什么目的?
【现在,我写的太多了,别人先回答了...
编辑:而且,正如Anton指出的那样,您需要$1
加载常量1,1
意味着从地址1读取,这不能很好地工作,并且很可能是问题的原因
希望不需要只使用 gcc 内联 asm 来弄清楚。你可以用nasm
翻译你的AT&T示例,然后用objdump
反汇编,看看什么是正确的语法。
我似乎记得,如果您的意思是文字常量而不是内存参考,mov 1,%eax
应该mov $1,%eax
。
@MatsPetersson的答案对于内联程序集与编译器(破坏/输入/输出寄存器)的交互非常有用。我专注于你得到SIGSEGV
的原因,阅读1
的地址确实回答了这个问题。
相关文章:
- 为什么我们不编写可以处理C++标识符的汇编器和链接器?
- 迭代器 for 循环不会确认循环完成条件
- 如何使用 gcc 内联汇编器代码访问成员变量
- 如何使用C 给出的地址覆盖汇编器堆栈的返回地址
- 与 2015 相比,内联汇编器给出了 C2400
- 在 c++ 中实现内联汇编器以对变量进行异或操作的正确方法
- C++迭代器"for loop"习惯用法,其步长> 1 并允许非随机访问反向迭代器
- 简单 g++ 内联汇编器中的错误
- C 汇编器转换问题
- 使用SSE将float值从汇编器DLL返回到C
- 内联汇编器直接双倍到长长转换
- 基于范围的 for 循环与常规迭代器 for 循环
- “__cpp”和 gcc 内联 ARM 汇编器
- 需要用C或C++编写MIPS汇编器,寻找一些设计建议
- 将 GCC/ATT 风格的汇编器转换为可视化工作室汇编器
- 如何使用内联汇编器保存寄存器值
- 调用传递给 gcc 内联汇编器 (avr-gcc) 的 const 函数地址
- 用汇编器消息编译错误
- 在Eclipse中,当使用汇编器时,汇编看起来是无限的
- 使用 AT&T 内联汇编器 for GCC