Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macos 执行“时导致SEGFULT”的简单内联汇编;你好,世界&引用;_Macos_Gcc_Assembly_X86 64_Inline Assembly - Fatal编程技术网

Macos 执行“时导致SEGFULT”的简单内联汇编;你好,世界&引用;

Macos 执行“时导致SEGFULT”的简单内联汇编;你好,世界&引用;,macos,gcc,assembly,x86-64,inline-assembly,Macos,Gcc,Assembly,X86 64,Inline Assembly,我试图让一些简单的c内联程序集从上到下工作。但我每次尝试执行时都会收到一个segfault。我正在使用OSX,所以我必须更改系统调用号。使用gdb,我想我找到了罪魁祸首:在执行exit syscall之后,它尝试执行存储“Hello world!”字符串的部分: void main() { __asm__ ( // print Hello World "movl $4, %eax;\n" /* 4 is the syscall number for write on osx *

我试图让一些简单的c内联程序集从上到下工作。但我每次尝试执行时都会收到一个segfault。我正在使用OSX,所以我必须更改系统调用号。使用gdb,我想我找到了罪魁祸首:在执行exit syscall之后,它尝试执行存储“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
);
}
正如您所看到的,我还试图完全跳过消息,结果没有产生任何输出


因此,如果这确实是导致segfault的原因,我如何防止消息执行?

在它之前添加一条
.data
语句。此外,您应该告诉gcc您正在烧掉
eax
ebx
ecx
注册表,这样之后的任何代码都可以工作(例如,gcc不会在asm块之前的
ecx
中放入某些内容,并期望它在asm块之后仍然存在)

通过以下方式执行此操作:

asm (
"your stuff"
"    .data\n"
"    .ascii ..."
:
:
: "a", "b", "c");

<强>更新:< /强>不同牌号的SysCurrar编号不同。例如,对于i38,退出SysCurrar数为1,但对于64位,则为60。相应地调整。考虑包括/Ur/Is/SysCurr.h,并使用其中的Y.NR**符号(它包含/Urr/IsAs/AsM/UnSt**h,其中有实际符号).

此代码基于可以找到的简单教程。我现在使用64位寄存器,64位系统调用值添加了0x2000000,我使用64位等效LEA来获取消息地址

如果您要在代码中使用asm块,并且这些块被其他C代码包围,那么您应该使用输入/输出约束和clobber列表。最好的信息在GCC中。我们销毁了大量寄存器(rax、rbx、rdx、rsi以及rcx、r11被
系统调用
)我们应该告诉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", "rcx", "r11"); /* list of clobbered registers */
}

。相反,使用此命令将字符串的地址从当前指令加载为16字节“-ohh,这是一个糟糕的计划,尤其是如果,例如,您插入了一条额外的指令…@MartinJames,那么我应该使用什么来代替呢?您确定这是系统调用约定OSX吗?您是否使用(OSX等效)进行了测试
strace
?Martin试图说明您已经摆脱了
“movl$message,%esi;\n”
这是以前的解决方案,它是一个更好的解决方案,并被一些有问题的解决方案所取代。您选择更改它的原因是什么?x64的调用约定不同。SYCALL号码不一样。此时,您将看到退出代码是
mov-rax,0x2000001
mov-rdi,0
syscall
这是完全不同的。它执行字符串的原因是因为错误的系统调用号没有使程序退出,然后它返回并继续。还要观察64位寄存器的使用情况(如rax而不是eax等)。该代码是英特尔语法。AT&T样式将是
mov$0x2000001,%rax
mov$0,%rdi
syscall
该代码尝试调用
exit
syscall来终止进程,因此所有这些都是无关的。OP需要找出
exit
失败的原因。他正在使用OSX,因此与Linux相关的帮助可能是无效的不太有用。@MichaelPetch任何符合posix的操作系统都可以自由定义不同的系统调用号,基于arch,32对64位,并使用各种输入方法,如int$0x80、syscall、sysenter等,以及哪些寄存器包含哪些参数。因此,这是有点相关的。我确信,有一个syscall.h等价物。是的,我正在使用Linux,并且得到了第二个系统调用上的一个segfault,我通过调整系统调用号修复了它。所以,它在大致范围内。执行硬连线16(eip)也有点不稳定,而不是执行lea消息。我的更新前回答是他最初猜测的正确答案。我不是你的下选民。但我的意思是,BSD系统调用不像在Linux中那样以u\NR作为前缀,并且在OS/X上,系统头不在/usr/include/asm中。我知道你不是,Jester是/曾经——他花了60秒。OSX确实有sys/syscall.h,手册页也引用了unistd.h。问题是相同的,无论是linux、OSX、BSD、solaris,一旦在一个操作系统中给出了解决方案(例如syscall.h),它很快就会在任何地方出现。linux都有syscall.h和sys/syscall.h[略有不同]。在OSX中,前缀不是_NR_uu[或sys_u],而是AUE_u[huh?-)],但概念是相似的。在我看来,任何做asm的人都必须能够读懂这篇文章的字里行间[或者坚持使用java:-)]很好的清理。OSX对32/64位系统调用(0x2000000)有一个有趣的解决方案。在某些方面,我更喜欢它。IIRC,您可以对xor和mov$1使用eXx regs[如果<32位],因为它将进行符号/零扩展。字节更少,执行速度更快。lea似乎是唯一一个需要r版本的寄存器,我个人知道32位寄存器可以被使用(lea指令除外),但为了回答这个问题,我想避免关于32位和64位寄存器使用的潜在问题;-),但是你的评论是正确的。我几乎添加了一个免责声明(我猜你可能知道),但是,我也觉得OP可能会阅读评论,并从中受益。而且,我是你的选民
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", "rcx", "r11"); /* list of clobbered registers */
}