我正在尝试从here开始使用一些简单的内联汇编。但每次我尝试执行它时,我都会收到一个段错误。我使用OS X所以我不得不更改系统调用号码。使用gdb我认为我确定了罪魁祸首:在执行退出系统调用之后,它尝试执行" Hello world!"字符串存储:
void main() {
__asm__ (
// print Hello World
"movl $4, %eax;\n" /* 4 is the syscall number for write on osx */
"movl $1, %ebx;\n" /* 1 is stdout and is the first argument */
// "movl $message, %esi;\n" /* load the address of string into the second argument*/
// instead use this to load the address of the string
// as 16 bytes from the current instruction
"leal 16(%eip), %ecx;\n"
"movl $13, %edx;\n" /* third argument is the length of the string to print*/
"syscall;\n"
// call exit (1 on osx) (so it doesn't try to run the string Hello World
"movl $1,%eax;\n"
"xorl %ebx,%ebx; \n"
"syscall;\n"
//"jmp ex;\n" here I tried to jump over the message, which results in no string being printed
// Store the Hello World inside the main function, results in segfault
"message: .ascii \"Hello World!\\n\";"
"ex:" //jump over message
);
}
正如你所看到的,我也试图完全跳过这条消息,而这又没有输出。
那么,如果这确实是导致段错误的原因,我怎么能阻止该消息的执行?
答案 0 :(得分:2)
此代码基于可以找到的简单教程here。我现在使用64位寄存器,64位 SYSCALL 值添加了0x2000000,我使用64位等效的 LEA 来获取地址消息
int main() {
__asm__ (
/* print Hello World */
"mov $0x2000004, %rax;\n" /* 0x2000004 is the syscall number for 64-bit osx */
"mov $1, %rbx;\n" /* 1 is stdout and is the first argument */
"lea message(%rip), %rsi\n" /* load the address of string into the second argument*/
"mov $13, %rdx;\n" /* third argument is the length of the string to print*/
"syscall;\n"
/* call exit (0x2000001 on osx) so it doesn't try to run the string Hello World */
"mov $0x2000001,%rax;\n"
"xor %rbx,%rbx; \n"
"syscall;\n"
/* Store the Hello World inside the main function, results in segfault */
"message: .ascii \"Hello World!\\n\";"
);
}
如果您要在代码中使用 asm 块并且它们被其他 C 代码包围,那么您应该使用输入/输出约束和clobber列表。最好的信息在 GCC Extended ASM documentation中。我们销毁了许多寄存器( rax , rbx , rdx , rsi ),我们应该告诉GCC 。使用扩展汇编语法时,您还必须使用%%
(而不仅仅是%
)为所有寄存器名称添加前缀。生成的 asm 块看起来像:
int main() {
__asm__ (
/* print Hello World */
"mov $0x2000004, %%rax;\n" /* 0x2000004 is the syscall number for 64-bit osx */
"mov $1, %%rbx;\n" /* 1 is stdout and is the first argument */
"lea message(%%rip), %%rsi\n" /* load the address of string into the second argument*/
"mov $13, %%rdx;\n" /* third argument is the length of the string to print*/
"syscall;\n"
/* call exit (1 on osx) (so it doesn't try to run the string Hello World */
"mov $0x2000001,%%rax;\n"
"xor %%rbx,%%rbx; \n"
"syscall;\n"
"message: .ascii \"Hello World!\\n\";"
: /* No output constraints */
: /* No input constraints */
: "rax", "rbx", "rdx","rsi"); /* list of clobbered registers */
}
答案 1 :(得分:0)
在其前面添加.data
语句。另外,您应该告诉gcc您正在刻录eax
,ebx
和ecx
个注册表,以便之后的任何代码都能正常工作(例如gcc赢了在 asm块之前ecx
中的某些内容,并希望它在之后仍然存在。
这样做:
asm (
"your stuff"
" .data\n"
" .ascii ..."
:
:
: "a", "b", "c");
更新:不同拱门的系统调用号码不同。例如,对于i386,退出系统调用编号为1,但对于64位,则为60.相应地进行调整。考虑包括/usr/include/syscall.h并在那里使用__NR_ *符号(它包括/usr/include/asm/unistd*.h,它们具有实际符号)。