上下文:为了更好地理解系统如何在Linux下工作,我正在尝试编写一个带有内联的小型C程序,该程序应该在x86_64系统上运行,并与gcc一起编译。
我的问题是:在这个环境中,syscall (例如写)是如何返回错误号的?我知道,当我使用像glibc这样的库时,它负责在全局errno变量中保存产生的错误代码。但是,当我通过内联汇编程序直接调用syscall时,错误号存储在哪里?它是存储在单独的寄存器中,还是用%rax编码?
让我们以linux上的写syscall为例:
当调用write时,在syscall返回之后,我发现它将0xfffffffffffffff2存储在%rax中,是否需要从其中提取错误代码?
如果我有错误代码号,应该在哪里查找以识别实际发生的错误?假设我返回了数字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 */
);使用result、msg和len定义如下:
long result = 0;
char* msg = "Hello World\n";
long len = 12;发布于 2016-05-11 15:55:21
Linux的惯例是,它们为返回值中的成功调用同时编码可能的错误代码和返回值。只是glibc或其他C库的包装器将errno设置为底层syscall返回的错误代码,包装器将返回-1。以write为例,内核进行类似于以下内容的错误处理:
ssize_t write(int fd, ...) {
if (fd is not valid)
return -EBADF;
return do_write(...);
}因此,正如您所看到的,错误代码只是在返回值中,根据语义,总是有一种方法可以通过将它与一个不可能成功操作的值进行比较来检查syscall是否成功。对于大多数系统(如write )来说,这意味着检查它是否为负。
发布于 2016-05-11 15:55:13
架构调用约定
正如您已经猜到的,您不能使用errno,因为它是GLibC特异性。如果rax是x86_64,您想要的信息将在x86_64中。手册页man 2 syscall有以下解释:
Architecture calling conventions
Every architecture has its own way of invoking and passing arguments
to the kernel. The details for various architectures are listed in
the two tables below.
The first table lists the instruction used to transition to kernel
mode (which might not be the fastest or best way to transition to the
kernel, so you might have to refer to vdso(7)), the register used to
indicate the system call number, the register used to return the
system call result, and the register used to signal an error.
arch/ABI instruction syscall # retval error Notes
────────────────────────────────────────────────────────────────────
alpha callsys v0 a0 a3 [1]
arc trap0 r8 r0 -
arm/OABI swi NR - a1 - [2]
arm/EABI swi 0x0 r7 r0 -
arm64 svc #0 x8 x0 -
blackfin excpt 0x0 P0 R0 -
i386 int $0x80 eax eax -
ia64 break 0x100000 r15 r8 r10 [1]
m68k trap #0 d0 d0 -
microblaze brki r14,8 r12 r3 -
mips syscall v0 v0 a3 [1]
nios2 trap r2 r2 r7
parisc ble 0x100(%sr2, %r0) r20 r28 -
powerpc sc r0 r3 r0 [1]
s390 svc 0 r1 r2 - [3]
s390x svc 0 r1 r2 - [3]
superh trap #0x17 r3 r0 - [4]
sparc/32 t 0x10 g1 o0 psr/csr [1]
sparc/64 t 0x6d g1 o0 psr/csr [1]
tile swint1 R10 R00 R01 [1]
x86_64 syscall rax rax - [5]
x32 syscall rax rax - [5]
xtensa syscall a2 a2 -和笔记号[5]
[5] The x32 ABI uses the same instruction as the x86_64 ABI and
is used on the same processors. To differentiate between
them, the bit mask __X32_SYSCALL_BIT is bitwise-ORed into the
system call number for system calls under the x32 ABI. Both
system call tables are available though, so setting the bit
is not a hard requirement.(在该手册页中,下面是一个表,显示如何将参数传递给系统调用。这是一个有趣的阅读。)
如何在此环境中从syscall (例如写)返回错误号?:
您必须检查您的rax寄存器的返回值。
发布于 2016-11-02 18:00:13
在Linux上,使用syscall程序集指令的系统调用失败将返回rax寄存器中的值-errno。所以在你的例子中,0-0xffffffffff 2,== 0xE,它是14,所以你的错误是14。
你怎么知道什么叫“差事14”?您应该在google上搜索"Linux错误代码表“,或者查看errno.h,这样就可以找到答案。
看看这里:http://www.virtsync.com/c-error-codes-include-errno
根据那张表,14是EFAULT,意思是“坏地址”。
https://stackoverflow.com/questions/37167141
复制相似问题