Hello all.
所以我正在学习装配 .
按照我通常的学习步骤,我接受任何新语言,我已经到了组装网络 .
其中,遗憾的是我没有那么顺利,因为我在第0步几乎失败了,这将获得一个可以开始通信的套接字 .
汇编代码应大致等于以下C代码:
#include <stdio.h>
#include <sys/socket.h>
int main(){
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
}
(让我们忽略它现在没有关闭套接字的事实 . )
所以这就是我到目前为止所做的事情:
- 已查看the manual . 这意味着我需要做一个
socketcall()
这一切都很好 . 问题始于它需要int
来描述它应该进行什么样的套接字调用 . 调用manpage对此没有多大帮助,因为它只描述了:
在某些体系结构上 - 例如,x86-64和ARM-没有socketcall()系统调用;相反,socket(2),accept(2),bind(2)等实际上是作为单独的系统调用实现的 .
- 然而在原始的系统调用列表中没有这样的调用 - 据我所知
socket()
,accept()
,bind()
,listen()
等是来自libnet
而不是来自内核的调用 . 这让我完全糊涂了所以我决定编译上面的C
代码并用strace
检查它 . 这产生了以下结果:
socket(PF_INET,SOCK_STREAM,IPPROTO_IP)= 3
- 虽然这没有让我更接近知道
socket()
is 它确实解释了它's arguments. For witch I don'似乎找到了适当的文件(再次) . 我认为PF_INET
,SOCK_STREAM
,IPPROTO_IP
将在<sys/socket.h>
中定义,但我的grep
-ing似乎没有找到任何用处 . 因此,我决定通过使用gdb
与disass main
串联来查找值 . 这给出了以下输出:
函数main的汇编代码转储:0x00000000004004fd <0>:push rbp 0x00000000004004fe <1>:mov rbp,rsp 0x0000000000400501 <4>:sub rsp,0x10 0x0000000000400505 <8>:mov edx,0x0 0x000000000040050a <13>:mov esi, 0x1 0x000000000040050f <18>:mov edi,0x2 0x0000000000400514 <23>:调用0x400400 0x0000000000400519 <28>:mov DWORD PTR [rbp-0x4],eax 0x000000000040051c <31>:离开
0x000000000040051d <32>:ret
汇编程序转储结束 .
-
根据我的经验,这意味着
socket()
从EDX
(PF_INET
),ESI
(SOCK_STREAM
)和EDI
(IPPROTO_IP
)获取它的参数 . 对于系统调用来说这是奇怪的(因为使用linux系统调用的约定是使用EAX
/RAX
作为调用编号,其他寄存器按递增顺序使用,例如.RBX
,RCX
,RDX
...) . 事实上这就是CALL
-ed而不是INT 0x80
'd这也意味着这实际上不是系统调用,而是从共享对象调用的东西 . 或者其他的东西 . -
但是又一次 . 在寄存器中传递参数对于
CALL
-ed来说非常奇怪 . 通常,据我所知,对于被调用的东西的参数应该是PUSH
-ed到堆栈上,因为编译器不知道他们会尝试使用哪些寄存器 . -
使用
ldd
检查生成的二进制文件时,此行为变得更加奇怪:
linux-vdso.so.1(0x00007fff4a7fc000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6(0x00007f56b0c61000)/lib64/ld-linux-x86-64.so.2(0x00007f56b1037000 )
- 似乎没有链接的网络库 .
这就是我已经没有想法了 .
所以我要求以下内容:
-
描述
x86-64
linux内核的实际系统调用及其相关数字的文档 . (最好作为C
的头文件 . ) -
定义
PF_INET
,SOCK_STREAM
,IPPROTO_IP
的头文件,因为它真的让我觉得我无法在自己的系统上找到它们 . -
也许是
x86-64
linux上的汇编联网教程 . (对于x86-32
,很容易找到材料,但出于某种原因,我对64位的东西空了 . )
谢谢!
1 回答
64位调用约定确实使用寄存器在用户空间和系统调用中传递参数 . 如您所见,用户空间约定是
rdi
,rsi
,rdx
,rcx
,r8
,r9
. 对于系统调用,使用r10
而不是rcx
,它被syscall指令破坏 . 有关详细信息,请参阅wikipedia或ABI文档 .各种常量的定义隐藏在头文件中,但是如果安装了必要的开发包,则可以通过文件系统搜索轻松找到它们 . 你应该查看
/usr/include/x86_64-linux-gnu/bits/socket.h
和/usr/include/linux/in.h
.至于系统调用列表,google one是微不足道的,例如this . 当然,您也可以始终查看内核源代码 .