4

过去的情况是,如果您需要在不使用现有库的情况下直接在 linux 中进行系统调用,您可以只包含<linux/unistd.h>它,它会定义一个类似于此的宏:

#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
  : "=a" (__res) \
  : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
      "d" ((long)(arg3))); \
if (__res>=0) \
  return (type) __res; \
errno=-__res; \
return -1; \
}

然后你可以在你的代码中的某个地方:

_syscall3(ssize_t, write, int, fd, const void *, buf, size_t, count);

这将为您定义一个write正确执行系统调用的函数。

似乎这个系统已经被某些东西取代了(我猜是每个进程都获得的“[vsyscall]”页面)更健壮。

那么程序直接在较新的linux内核上执行系统调用的正确方法是什么(请具体说明)?我意识到我应该使用 libc 并让它为我完成工作。但是让我们假设我有充分的理由想知道如何做到这一点:-)。

4

1 回答 1

4

好的,所以我进一步研究了它,因为我在这里没有得到太多回应,并找到了一些很好的信息。首先在linux中启动应用程序时,除了传统的argc、argv、envp参数。还有另一个数组传递了一些称为 auxv 的更多数据。有关详细信息,请参见此处

这些键/值对之一具有等效于 的键AT_SYSINFO。在/usr/include/asm/auxvec.h或中定义/usr/include/elf

与此键关联的值是系统调用函数的入口点(在映射到每个进程的“vdso”或“vsyscall”页面中。

You could just replace the traditional int 0x80 or syscall instructions with a call to this address and it would actually do the system call. Unfortunately, this is ugly. So the libc folks come up with a nice solution. When they allocate the TCB and assign it to the gs segment. They put the value of AT_SYSINFO in some fixed offset in the TCB (unfortunately it isn't fixed across versions so you can't rely on the offset being a the same constant always). So instead of a traditional int 0x80 you can just say call *%gs:0x10 which will call the system call routine found in the vdso section.

I suppose the goal here is to make writing libc easier. This allows the libc guys to write one block of code to deal with system calls and not have to worry about it ever again. The kernel guys can change how system calls are done at any point in time, they just need to change the contents of the vdso page to use the new mechanism and it's good to go. In fact, you wouldn't need to even recompile your libc! However, this does make things a pain in the butt for us people writing inline assembly and trying to play with the things under the hood.

Fortunately the old way still works too if you really want to do things manually :-).

EDIT: one thing I've noticed with my experiements is that AT_SYSINFO doesn't seem to be given to the program on my x86_64 box (AT_SYSINFO_EHDR is, but i'm not sure how to make use of that yet). So I'm not 100% sure how the address of the system call function is determined in this situation.

于 2010-05-24T15:51:03.643 回答