首页 文章

Linux x86_64汇编套接字编程

提问于
浏览
2

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_INETSOCK_STREAMIPPROTO_IP 将在 <sys/socket.h> 中定义,但我的 grep -ing似乎没有找到任何用处 . 因此,我决定通过使用 gdbdisass 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()EDXPF_INET ), ESISOCK_STREAM )和 EDIIPPROTO_IP )获取它的参数 . 对于系统调用来说这是奇怪的(因为使用linux系统调用的约定是使用 EAX / RAX 作为调用编号,其他寄存器按递增顺序使用,例如. RBXRCXRDX ...) . 事实上这就是 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_INETSOCK_STREAMIPPROTO_IP 的头文件,因为它真的让我觉得我无法在自己的系统上找到它们 .

  • 也许是 x86-64 linux上的汇编联网教程 . (对于 x86-32 ,很容易找到材料,但出于某种原因,我对64位的东西空了 . )

谢谢!

1 回答

  • 2

    64位调用约定确实使用寄存器在用户空间和系统调用中传递参数 . 如您所见,用户空间约定是 rdirsirdxrcxr8r9 . 对于系统调用,使用 r10 而不是 rcx ,它被syscall指令破坏 . 有关详细信息,请参阅wikipedia或ABI文档 .

    各种常量的定义隐藏在头文件中,但是如果安装了必要的开发包,则可以通过文件系统搜索轻松找到它们 . 你应该查看 /usr/include/x86_64-linux-gnu/bits/socket.h/usr/include/linux/in.h .

    至于系统调用列表,google one是微不足道的,例如this . 当然,您也可以始终查看内核源代码 .

相关问题