网络的机器代码是什么样的?

时间:2012-04-08 19:27:49

标签: c windows linux assembly ipc

在一天结束时,我们编写的每一段代码最终都会变成汇编程序,然后变成机器语言。

如果您正在编写汇编程序并希望在两台计算机之间执行简单连接,那么您如何知道在汇编程序中使用哪些内存地址(更不用说偏移)?您需要知道与操作系统相关的具体地址吗?

我只是想知道有人会如何编写一个真正“干净”和“高效”的消息传递库/编译器 - 让我这样的东西是网络通信/ IPC在汇编程序中的样子?

我认为这个答案的一部分可能在于查询与操作系统相关的已知地址?例如,0x4545456到0x 60000000包含用于通信X等的Linux内核数据。

2 个答案:

答案 0 :(得分:1)

地址并非特定于您的操作系统。它们特定于您的硬件/系统。访问它们与汇编程序与另一种编程语言(例如C)无关,实际上大多数设备驱动程序代码(实际与网络硬件交互的代码)通常用C语言编写。

这里只是网络(以太网)控制器的一个随机样本:

Intel® 82580EB/82580DB GbE Controller: Datasheet

有许多寄存器,您的软件(无论是汇编程序还是其他语言)必须编程才能通过以太网进行实际通信。从一个更简单的例子开始,可能更容易,比如串口。让我们构建一个假设的,固定的波特率,串口控制器,映射到内存:

Address  Meaning
0        RX status (reads 0 when no data to read, 1 a byte is available)
1        RX buffer
2        TX status (reads 0 when ready to send, 1 when busy)
3        TX buffer

现在,您的软件(使用汇编程序或任何其他语言)可以通过监视(轮询)地址2将数据传输到另一台计算机,直到它准备就绪,将下一个字节写入地址3.我们也可以通过另一台计算机接收数据监视(轮询)地址0以查看数据何时就绪,并在数据存在时从地址1读取字节。

在现代操作系统/操作系统中,所有物理地址都需要以某种方式映射到虚拟地址。

真实世界的硬件,例如我链接的硬件,通常会使用中断,因此您无需轮询。它通常具有DMA,因此硬件可以直接访问您的数据,而不是逐字节地提供数据。它将处理各种协议,并将具有用于检查和设置此协议的各个方面的寄存器。

在现代操作系统中,与硬件的实际交互在device driver中实现,用户软件可以通过某些API与设备驱动程序交换数据。同样,该用户代码可以用汇编语言或任何其他语言编写。 API将根据操作系统的不同而有所不同。通信/网络通常构建为“stack”,在较低级别的协议上实施更高级别的协议。该堆栈的哪个部分位于用户库或操作系统的一部分将在不同的操作系统之间变化。

对于我上面描述的假设设备,API可能包含两个单字节阻塞调用read()write()。然后,您可以使用汇编程序或更高级语言中的某种system call机制来调用这些机制并传递参数/检索输出。在某些操作系统中,设备I / O可能看起来像文件I / O,因此您将使用通用文件读/写来对设备执行操作,操作系统会将这些操作分配给正确的设备驱动程序。此外,在典型的操作系统中,实际的系统调用将通过某种类型的库提供,您可以使用各种编程语言调用它。

答案 1 :(得分:0)

在汇编中进行联网有两段代码 - 操作系统用来实际进行网络连接的内核代码,以及想要告诉操作系统通过网络发送什么数据的客户端代码。

通常,机器中的硬件具有专用于与网络硬件通信的某些存储器地址。然后,OS的机器代码可以将适当的值写入该存储器,以控制最终发送和接收字节的硬件。这些内存地址将被硬编码到机器代码中。

对于进行网络连接的用户代码(例如,Mozilla Firefox),过程是不同的。通常有一个机器指令或一组指令用于用户代码告诉操作系统执行某些任务(例如,MIPS,这是syscall,而我认为x86使用int }指令)。客户端代码可以通过设置一些具有相应数据的缓冲区来发送到网络,然后使用上面的汇编指令告诉操作系统它应该发送数据。然后硬件调用OS,OS读取用户数据,然后使用其自己的机器代码(如上所述)来实际控制网络设备。通过这种方式,OS可以通过阻止对控制设备的物理地址的访问以及通过系统调用来调节访问来保护对网络设备的直接访问。这也意味着在编写用户代码进行网络连接时,您不需要知道任何内存地址。操作系统处理这些细节,您需要知道的是执行什么指令来触发系统调用。

希望这有帮助!