从C ++调用汇编代码

时间:2016-02-19 20:32:37

标签: c++ c linux x86-64 inline-assembly

我正在尝试编写自己的I / O库,因此第一步就是能够输出一个字符。到目前为止,这只需要在Linux上运行。我在x86(使用Intel语法)中编写了我认为是一个可靠的%declare CMD `$mycmd $date` A = load '/data/mydata/$CMD'; B = filter A by $0>'5'; 标签,然后将其放入" io.h",然后从我的主文件中调用它,&#34 ; TEST.CPP&#34 ;.这是test.cpp的内容:

_putc:

这是我的io.h:

#include "io.h"
extern void _putc(char) __asm__("_putc");
int main(int argc, char** argv){
    _putc('c');
    return 0;
}

我是在x86_64 Linux操作系统上使用 G ++

进行开发的

我用它来编译:

asm(
"\n.intel_syntax noprefix"
"\n.globl _putc"
"\n_putc:"
"\n\tpush [ebp]"
"\n\tmov ebp,esp"
"\n\tmov eax,4"
"\n\tmov ebx,0"
"\n\tmov ecx,[ebp+8]"
"\n\tmov edx,1"
"\n\tint 0x80"
"\n\tret"
"\n.att_syntax" ;return to g++'s at&t syntax
);

立即运行时会出现段错误。我认为我的问题是召集会议,但是没有办法绝对肯定。我尝试在一个函数( g++ -o test test.cpp -Wall )中包装程序集并删除全局标签,但这没有帮助。我也尝试推送void _putc(char c)的内容而不是它指向的内容,但它不会编译。

注意:这必须只与主文件中的行ebp一起使用(我可以在此工作后移动#include io.h),并且必须使用 C ++ ,而不仅仅是 C 。另外,请不要在头文件中告诉我有关函数定义的信息,这正是我正在做的事情。

1 个答案:

答案 0 :(得分:3)

使用64位代码,您确实需要考虑使用syscall而不是int 0x80。系统调用使用64位约定,系统调用号与32位代码中的int 0x80不同。您可以在table中了解64位系统调用。 sys_writesys_read来电显示如下:

%rax  System call %rdi              %rsi             %rdx         %r10      %r8   %r9
0     sys_read    unsigned int fd   char *buf        size_t count         
1     sys_write   unsigned int fd   const char *buf  size_t count

如果您想了解如何在64位Linux代码中传递参数,您需要熟悉System V 64-Linux ABI。在输入调用之后,如果您打算调用其他函数或系统调用,通常必须将堆栈对齐到16字节边界。

您的代码也会遇到将角色传递给sys_write的缺陷。 sys_write需要一个包含字符的缓冲区的地址,而不是字符本身。

这是一个可以工作的代码转储:

asm(
"\n.intel_syntax noprefix"
"\n.globl _putc"
"\n_putc:"
"\n\tadd rsp, -8"   // Allocate space on the stack to store the character passed
                    // Also aligns stack back to 16-bye boundary 
                    // with return address already on stack
"\n\tmov [rsp],rdi" // Move the character passed in RDI to memory(stack) for sys_write
"\n\tmov eax,1"     // With 64-bit syscalls RAX = 1 for sys_write
"\n\txor edi,edi"   // 1st parameter to syscall is in RDX. FD = 0
"\n\tlea rsi,[rsp]" // We need to pass pointer to memory containing our char
"\n\tmov edx,1"     // RDX = 1 character to print. Could reuse EAX instead of 1 for src
"\n\tsyscall"       // Make syscall (using syscall instead of int 0x80 for 64-bit)

"\n\tadd rsp, 8"    // Restore stack to state right after function entry
"\n\tret"
"\n.att_syntax prefix" //return to g++'s at&t syntax
);