汇编中系统调用的返回值是什么? [英] What are the return values of system calls in Assembly?

查看:33
本文介绍了汇编中系统调用的返回值是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试研究内核系统调用的返回值时,我找到了描述它们的表,以及我需要在不同的寄存器中放入什么才能让它们工作.但是,我没有找到任何说明什么是我从系统调用中获得的返回值的文档.我只是在不同的地方发现我收到的将在 EAX 寄存器中.

When I try to research about return values of system calls of the kernel, I find tables that describe them and what do I need to put in the different registers to let them work. However, I don't find any documentation where it states what is that return value I get from the system call. I'm just finding in different places that what I receive will be in the EAX register.

教程要点:

结果通常在 EAX 寄存器中返回.

The result is usually returned in the EAX register.

Assembly Language Step-By-Step: Programming with Linux Jeff Duntemann 在他的程序中多次说明:

Assembly Language Step-By-Step: Programming with Linux book by Jeff Duntemann states many times in his programs:

  • 查看EAX中sys_read的返回值

复制 sys_read 返回值以安全保存


我访问过的任何网站都没有解释这个返回值.有没有互联网资源?或者有人可以向我解释这个值吗?


Any of the websites I have don't explain about this return value. Is there any Internet source? Or can someone explain me about this values?

推荐答案

另见 这篇关于系统的优秀 LWN 文章调用 假设 C 知识.

See also this excellent LWN article about system calls which assumes C knowledge.

另外:Linux 系统调用权威指南(在 x86 上),以及相关内容:如果在 64 位代码中使用 32 位 int 0x80 Linux ABI 会怎样?

Also: The Definitive Guide to Linux System Calls (on x86), and related: What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?

C 是 Unix 系统编程的语言,所以所有的文档都是用 C 语言编写的.然后有关于 C 接口和任何给定平台上的 asm 之间的细微差别的文档,通常在手册页的注释部分.

C is the language of Unix systems programming, so all the documentation is in terms of C. And then there's documentation for the minor differences between the C interface and the asm on any given platform, usually in the Notes section of man pages.

sys_read 表示原始系统调用(与 libc 包装函数相反).read 系统调用的内核实现是一个名为 sys_read() 的内核函数.你不能用 call 指令调用它,因为它在内核中,而不是库中.但是人们仍然谈论调用 sys_read"以区别于 libc 函数调用.但是,即使您指的是原始系统调用(尤其是当 libc 包装器没有做任何特别的事情时),也可以说 read,就像我在这个答案中所做的那样.

sys_read means the raw system call (as opposed to the libc wrapper function). The kernel implementation of the read system call is a kernel function called sys_read(). You can't call it with a call instruction, because it's in the kernel, not a library. But people still talk about "calling sys_read" to distinguish it from the libc function call. However, it's ok to say read even when you mean the raw system call (especially when the libc wrapper doesn't do anything special), like I do in this answer.

另请注意,syscall.h 定义了诸如 SYS_read 之类的常量,带有实际的系统调用号,或者 asm/unistd.h 用于 Linux__NR_read 相同常量的名称.(您在 int 0x80syscall 指令之前放入 EAX 中的值).

Also note that syscall.h defines constants like SYS_read with the actual system call number, or asm/unistd.h for the Linux __NR_read names for the same constants. (The value you put in EAX before an int 0x80 or syscall instruction).

Linux 系统调用返回值(在 x86 上的 EAX/RAX 中)要么是正常的",要么是正常的".成功,或 -errno 代码 表示错误.例如-EFAULT 如果你传递了一个无效的指针.此行为记录在 syscalls(2) 手册页.

Linux system call return values (in EAX/RAX on x86) are either "normal" success, or a -errno code for error. e.g. -EFAULT if you pass an invalid pointer. This behaviour is documented in the syscalls(2) man page.

-1 到 -4095 表示错误,其他任何表示成功.请参阅AOSP non-obvious syscall() 实现,了解更多详情-4095UL .. -1UL 范围,可在 Linux 上跨架构移植,适用于每个系统调用.(在未来,不同的架构可能会使用不同的 MAX_ERRNO 值,但是像 x86-64 这样的现有架构的值保证与 Linus 保持内核 ABI 稳定的不破坏用户空间策略的一部分保持相同.)

-1 to -4095 means error, anything else means success. See AOSP non-obvious syscall() implementation for more details on this -4095UL .. -1UL range, which is portable across architectures on Linux, and applies to every system call. (In the future, a different architecture could use a different value for MAX_ERRNO, but the value for existing arches like x86-64 is guaranteed to stay the same as part of Linus's don't-break-userspace policy of keeping kernel ABIs stable.)

例如glibc的通用syscall(2) 包装函数使用这个序列:cmp rax, -4095/jae SYSCALL_ERROR_LABEL,即保证所有 Linux 系统调用都面向未来.

For example, glibc's generic syscall(2) wrapper function uses this sequence: cmp rax, -4095 / jae SYSCALL_ERROR_LABEL, which is guaranteed to be future-proof for all Linux system calls.

您可以使用该包装函数进行任何系统调用,例如 syscall( __NR_mmap, ... ).(或者使用像 https://github.com/linux-on-ibm-z/linux-syscall-support/blob/master/linux_syscall_support.h 为多个 ISA 提供安全的 inline-asm,避免丢失<代码>内存" clobbers 其他一些内联 asm 包装器所具有的.)

You can use that wrapper function to make any system call, like syscall( __NR_mmap, ... ). (Or use an inline-asm wrapper header like https://github.com/linux-on-ibm-z/linux-syscall-support/blob/master/linux_syscall_support.h that has safe inline-asm for multiple ISAs, avoiding problems like missing "memory" clobbers that some other inline-asm wrappers have.)

有趣的例子包括 getpriority,其中内核 ABI 将 -20..19 返回值范围映射到 1..40,然后 libc 对其进行解码.有关解码系统调用错误返回值的相关答案中的更多详细信息.

Interesting cases include getpriority where the kernel ABI maps the -20..19 return-value range to 1..40, and libc decodes it. More details in a related answer about decoding syscall error return values.

对于 mmap,如果您愿意,您还可以通过检查返回值是否未按页面对齐来检测错误(例如,低 11 中的任何非零位,对于 4k 页面大小),如果那样的话比检查 p > 更有效-4096ULL.

For mmap, if you wanted you could also detect error just by checking that the return value isn't page-aligned (e.g. any non-zero bits in the low 11, for a 4k page size), if that would be more efficient than checking p > -4096ULL.

要查找特定平台的常量的实际数值,您需要找到它们 #defined 的 C 头文件.有关详细信息,请参阅我对此问题的回答.例如在 asm-generic/errno-base.h/asm-generic/errno.h 中.

To find the actual numeric values of constants for a specific platform, you need to find the C header file where they're #defined. See my answer on a question about that for details. e.g. in asm-generic/errno-base.h / asm-generic/errno.h.

每个 sys 调用的返回值的含义记录在第 2 部分手册页中,例如 read(2).(sys_read 是原始系统调用,glibc read() 函数是一个非常薄的包装器.)大多数手册页都有一个完整的返回值部分.例如

The meanings of return values for each sys call are documented in the section 2 man pages, like read(2). (sys_read is the raw system call that the glibc read() function is a very thin wrapper for.) Most man pages have a whole section for the return value. e.g.

返回值

成功时返回读取的字节数(零表示文件结尾),文件位置按此数字前进.它如果此数字小于字节数,则不是错误要求;这可能会发生,例如因为较少的字节
现在实际可用(可能是因为我们即将结束-
文件,或者因为我们正在从管道或终端读取),或
因为 read() 被信号中断了.另请参阅注释.

On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are
actually available right now (maybe because we were close to end-of-
file, or because we are reading from a pipe, or from a terminal), or
because read() was interrupted by a signal. See also NOTES.

出错时,返回-1,并适当设置errno.在这情况下,未指定文件位置(如果有)
变化.

On error, -1 is returned, and errno is set appropriately. In this case, it is left unspecified whether the file position (if any)
changes.

请注意,最后一段描述了 glibc 包装器如何解码值和 设置 errno-EAX 如果原始系统调用的返回值为负,那么 errno=EFAULT 并返回 -1 如果原始系统调用返回 -EFAULT.

Note that the last paragraph describes how the glibc wrapper decodes the value and sets errno to -EAX if the raw system call's return value is negative, so errno=EFAULT and return -1 if the raw system call returned -EFAULT.

有一整节列出了允许 read() 返回的所有可能的错误代码,以及它们对 read() 的具体含义.(POSIX 标准化了大部分这种行为.)

And there's a whole section listing all the possible error codes that read() is allowed to return, and what they mean specifically for read(). (POSIX standardizes most of this behaviour.)

这篇关于汇编中系统调用的返回值是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆