【发布时间】:2018-10-29 19:23:36
【问题描述】:
我在解决学校练习时遇到问题,我应该使用内联汇编更改 c 中的 char 数组。在这种情况下,将“ahoy”更改为“aXoy”,但我遇到了分段错误。这是我的代码:
#include <stdio.h>
int main() {
char string[] = "ahoy";
__asm__ volatile (
"mov %0, %%eax;"
"movb $'X', 1(%%eax);"
: "=m"(string) : "0"(string) : "memory", "eax");
printf("%s\n", string);
return 0
}
用这个:"mov %0, %%eax;" 我正在尝试将数组的地址存储在寄存器中
然后用这个:"movb $'X', 1(%%eax);" 我想将字节“X”存储在 (%%eax) 偏移 1 个字节(char) 所指向的位置,
我有字符串作为输出和输入,以及 clobber 中的“memory”、“eax”,因为我正在修改两者。我的代码有什么问题?
【问题讨论】:
-
如果您想使用
string作为输入和输出,请将其标记为"+m"而不是"=m",然后完全删除"0"(string)。这行mov %0, %%eax;会将内存地址处的 32 位值移动到 EAX,因为 %0 是内存操作数。你想把 %0 的地址放在它出现的 EAX 中。使用lea %0, %%eax;而不是mov %0, %%eax; -
其次:你是编译成 64 位还是 32 位代码?内联汇编使用 32 位寄存器和基于堆栈的地址 (
string) 将出错,因为堆栈地址无法以 32 位值正确表示。确保使用-m32编译它或修改代码以使用 64 位寄存器作为地址(RAX 而不是 EAX) -
__asm__ volatile ( "lea %0, %%eax;" "movb $'X', 1(%%eax);" : "+m"(string) :: "memory", "eax"); -
+修饰符几乎永远存在。它们都记录在这里:gcc.gnu.org/onlinedocs/gcc/Modifiers.html#Modifiers -
从技术上讲,在这种情况下使用
+m,您不需要使用memoryclobber,因为编译器将首先在内存中实现所有string,因为您使用的是@987654339 @ 约束。或者,您可以完成__asm__ volatile ( "movb $'X', 1(%0);" :: "r"(string) : "memory");。需要内存破坏器,因为在这种情况下,您通过寄存器而不是内存操作数传递string的地址。
标签: c assembly x86 inline-assembly cpu-registers