上下文:我正在尝试使用内联asm编写一个小型C程序,它应该在x86_64系统上的
Linux下运行并使用gcc编译,以便更好地理解系统调用在Linux下的工作方式.
我的问题是:在这种环境中,如何从系统调用(例如写入)返回错误号码?我知道当我使用像glibc这样的库时,它会在全局errno变量中保存生成的错误代码.但是当我通过内联汇编程序直接调用系统调用时,存储的错误号在哪里?它会存储在一个单独的寄存器中,还是会在%rax中编码?
我们以linux上的write syscall为例:
当调用写入然后在系统调用返回后我发现它在%rax内存储0xfffffffffffffff2,我是否需要
以某种方式从中提取错误代码?
如果我有错误代码编号,我应该在哪里找出发生的实际错误?让我说我得到了返回的数字5,我需要咨询哪个头文件以找到相应的符号错误名称.
asm ("mov $1,%%rax;" "mov $1,%%rdi;" "mov %1,%%rsi;" "mov %2,%%rdx;" "syscall;" "mov %%rax,%0;" : "=r" (result) : "r" (msg),"r" (len) : "%rdx","%rsi","%rax","%rdi" /* EDIT: this is needed or else the registers will be overwritten */ );
结果,msg和len定义如下:
long result = 0; char* msg = "Hello World\n"; long len = 12;
解决方法
linux系统调用的惯例是它们在返回值中编码可能的错误代码和成功调用的返回值.它只是glibc或其他C库的包装器,它们将错误代码设置为由下划线系统调用返回的错误代码,并且包装器将返回-1.以write为例,内核执行与此类似的错误处理:
ssize_t write(int fd,...) { if (fd is not valid) return -EBADF; return do_write(...); }
正如您所看到的,错误代码只是在返回值中,并且根据语义,始终有一种方法可以通过将系统调用与成功操作不可能的值进行比较来检查系统调用是否成功.对于大多数系统调用,如写入调用,这意味着检查它是否为负数.