- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我剖析了最后一个 libc 中的系统调用:
git clone git://sourceware.org/git/glibc.git
我在 sysdeps/unix/sysv/linux/i386/sysdep.h 中有这段代码:
# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
LOADREGS_##nr(args) \
asm volatile ( \
"call *%%gs:%P2" \
: "=a" (resultvar) \
: "a" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \
ASMARGS_##nr(args) : "memory", "cc")
如果我很好地理解这段代码,LOADREGS_##nr(args) 宏将参数加载到寄存器 ebx、ecx、edx、esi、edx 和 ebp 中。
sysdeps/unix/sysv/linux/i386/sysdep.h
# define LOADREGS_0()
# define ASMARGS_0()
# define LOADREGS_1(arg1) \
LOADREGS_0 ()
# define ASMARGS_1(arg1) \
ASMARGS_0 (), "b" ((unsigned int) (arg1))
# define LOADREGS_2(arg1, arg2) \
LOADREGS_1 (arg1)
# define ASMARGS_2(arg1, arg2) \
ASMARGS_1 (arg1), "c" ((unsigned int) (arg2))
# define LOADREGS_3(arg1, arg2, arg3) \
LOADREGS_2 (arg1, arg2)
# define ASMARGS_3(arg1, arg2, arg3) \
ASMARGS_2 (arg1, arg2), "d" ((unsigned int) (arg3))
# define LOADREGS_4(arg1, arg2, arg3, arg4) \
LOADREGS_3 (arg1, arg2, arg3)
# define ASMARGS_4(arg1, arg2, arg3, arg4) \
ASMARGS_3 (arg1, arg2, arg3), "S" ((unsigned int) (arg4))
# define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \
LOADREGS_4 (arg1, arg2, arg3, arg4)
# define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \
ASMARGS_4 (arg1, arg2, arg3, arg4), "D" ((unsigned int) (arg5))
# define LOADREGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \
register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \
LOADREGS_5 (arg1, arg2, arg3, arg4, arg5)
# define ASMARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \
ASMARGS_5 (arg1, arg2, arg3, arg4, arg5), "r" (_a6)
#endif /* GCC 5 */
enter code here
将参数加载到寄存器 ebx、ecx、edx、esi、edx 和 ebp 的代码在哪里?是上面这段代码吗?我不明白实现。以下代码将第 6 个参数加载到 ebx 寄存器中?
register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6);
这段代码是做什么的:
ASMARGS_0 (), "b" ((unsigned int) (arg1))
它加载 ebx 寄存器中的第一个参数?
然后“call *%%gs:%P2”跳转到VDSO代码?此代码对应于“call *gs:0x10”?
所以,下面这个写入系统调用的图表,它很好吗?:
write(1, "A", 1) -----> LIBC -----> VDSO -----> KERNEL
load reg ?
jump to vdso
|---------------------------------------------------|--------------|
user land kernel land
我不明白 VDSO 实用程序! vdso 选择系统调用方法(sysenter 或 int 0x80)。
预先感谢您的帮助。抱歉,我的英语很烂。
最佳答案
以 exit 系统调用为例,glibc 系统调用中涉及的宏将扩展为如下内容。
LOADREGS_1(args)
asm volatile (
"call *%%gs:%P2"
: "=a" (resultvar)
: "a" (__NR_exit), "i" (offsetof (tcbhead_t, sysinfo))
ASMARGS_1(args) : "memory", "cc")
LOADREGS_1(args)
将扩展为 LOADREGS_0()
,这将扩展为空 - LOADREGS_*(...)
只需要在提供更多参数时调整寄存器。
ASMARGS_1(args)
将扩展为 ASMARGS_0(), "b"((unsigned int) (arg1))
,这将扩展为 , "b"((unsigned int) (arg1)
。
__NR_exit
在 x86 上为 1。
因此,代码将扩展为:
asm volatile (
"call *%%gs:%P2"
: "=a" (resultvar)
: "a" (1), "i" (offsetof (tcbhead_t, sysinfo))
, "b" ((unsigned int) (arg1) : "memory", "cc")
ASMARGS_*
实际上并不执行代码本身 - 它们是对 gcc
的指令,以确保某些值(例如(unsigned int) (arg1)
) 在某些寄存器中(例如 b
,又名 ebx
)。因此,asm volatile
的参数组合(当然,这不是一个函数,而只是一个 gcc 内置函数)简单地指定了 gcc
应该如何为系统调用做准备以及在系统调用完成后它应该如何继续。
现在,生成的程序集看起来像这样:
; set up other registers...
movl $1, %eax
call *%gs:0x10
; tear down
%gs
是引用线程本地存储的段寄存器 - 具体来说,glibc 引用指向 VDSO 的已保存值,它在第一次解析 ELF header 时存储在那里VDSO 所在的位置。
一旦代码进入 VDSO,我们不知道到底发生了什么——它因内核版本而异——但我们知道它使用最有效的可用机制来运行系统调用,例如 sysenter
指令或 int 0x80
指令。
所以,是的,你的图表是准确的:
write(1, "A", 1) -----> LIBC -----> VDSO -----> KERNEL
load reg ?
jump to vdso
|---------------------------------------------------|--------------|
user land kernel land
这是调用 VDSO 的一个更简单的代码示例,专门用于单参数系统调用,来 self 维护的库 libsyscall :
_lsc_syscall1:
xchgl 8(%esp), %ebx
movl 4(%esp), %eax
call *_lsc_vdso_ptr(,1)
movl 8(%esp), %ebx
# pass %eax out
ret
这只是将参数从堆栈移入寄存器,通过从内存加载的指针调用 VDSO,将其他寄存器恢复到它们之前的状态,并返回系统调用的结果。
关于c - Linux 系统调用、libc、VDSO 和实现剖析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35115470/
为了让我的代码几乎完全用 Jquery 编写,我想用 Jquery 重写 AJAX 调用。 这是从网页到 Tomcat servlet 的调用。 我目前情况的类似代码: var http = new
我想使用 JNI 从 Java 调用 C 函数。在 C 函数中,我想创建一个 JVM 并调用一些 Java 对象。当我尝试创建 JVM 时,JNI_CreateJavaVM 返回 -1。 所以,我想知
环顾四周,我发现从 HTML 调用 Javascript 函数的最佳方法是将函数本身放在 HTML 中,而不是外部 Javascript 文件。所以我一直在网上四处寻找,找到了一些简短的教程,我可以根
我有这个组件: import {Component} from 'angular2/core'; import {UserServices} from '../services/UserService
我正在尝试用 C 实现一个简单的 OpenSSL 客户端/服务器模型,并且对 BIO_* 调用的使用感到好奇,与原始 SSL_* 调用相比,它允许一些不错的功能。 我对此比较陌生,所以我可能会完全错误
我正在处理有关异步调用的难题: 一个 JQuery 函数在用户点击时执行,然后调用一个 php 文件来检查用户输入是否与数据库中已有的信息重叠。如果是这样,则应提示用户确认是否要继续或取消,如果他单击
我有以下类(class)。 public Task { public static Task getInstance(String taskName) { return new
嘿,我正在构建一个小游戏,我正在通过制作一个数字 vector 来创建关卡,该数字 vector 通过枚举与 1-4 种颜色相关联。问题是循环(在 Simon::loadChallenge 中)我将颜
我有一个java spring boot api(数据接收器),客户端调用它来保存一些数据。一旦我完成了数据的持久化,我想进行另一个 api 调用(应该处理持久化的数据 - 数据聚合器),它应该自行异
首先,这涉及桌面应用程序而不是 ASP .Net 应用程序。 我已经为我的项目添加了一个 Web 引用,并构建了各种数据对象,例如 PayerInfo、Address 和 CreditCard。但问题
我如何告诉 FAKE 编译 .fs文件使用 fsc ? 解释如何传递参数的奖励积分,如 -a和 -target:dll . 编辑:我应该澄清一下,我正在尝试在没有 MSBuild/xbuild/.sl
我使用下划线模板配置了一个简单的主干模型和 View 。两个单独的 API 使用完全相同的配置。 API 1 按预期工作。 要重现该问题,请注释掉 API 1 的 URL,并取消注释 API 2 的
我不确定什么是更好的做法或更现实的做法。我希望从头开始创建目录系统,但不确定最佳方法是什么。 我想我在需要显示信息时使用对象,例如 info.php?id=100。有这样的代码用于显示 Game.cl
from datetime import timedelta class A: def __abs__(self): return -self class B1(A):
我在操作此生命游戏示例代码中的数组时遇到问题。 情况: “生命游戏”是约翰·康威发明的一种细胞自动化技术。它由一个细胞网格组成,这些细胞可以根据数学规则生存/死亡/繁殖。该网格中的活细胞和死细胞通过
如果我像这样调用 read() 来读取文件: unsigned char buf[512]; memset(buf, 0, sizeof(unsigned char) * 512); int fd;
我用 C 编写了一个简单的服务器,并希望调用它的功能与调用其他 C 守护程序的功能相同(例如使用 ./ftpd start 调用它并使用 ./ftpd stop 关闭该实例)。显然我遇到的问题是我不知
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
我希望能够从 cmd 在我的 Windows 10 计算机上调用 python3。 我已重新安装 Python3.7 以确保选择“添加到路径”选项,但仍无法调用 python3 并使 CMD 启动 P
我是一名优秀的程序员,十分优秀!