这些地址并不特定于您的操作系统。它们特定于您的硬件/系统。访问这些与汇编程序与另一种编程语言(例如 C)无关,实际上大多数设备驱动程序代码(实际与网络硬件交互的代码)通常是用 C 编写的。
这只是网络(以太网)控制器的一个随机样本:
英特尔® 82580EB/82580DB GbE 控制器:数据表
您的软件(无论是汇编程序还是其他语言)都必须对大量寄存器进行编程,以使该事物能够通过以太网进行实际通信。从一个更简单的例子开始可能更容易,比如串行端口。让我们构建一个假设的、固定波特率的串行端口控制器,映射到内存:
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,因此硬件可以直接访问您的数据,而不是您逐字节地输入数据。它将处理各种协议,并将具有用于检查和设置该协议各个方面的寄存器。
在现代操作系统中,与硬件的实际交互是在设备驱动程序中实现的,用户软件可以通过一些 API 与设备驱动程序交换数据。同样,此用户代码可以用汇编程序或任何其他语言编写。API 会因操作系统而异。通信/网络通常构建为“堆栈”,在较低级别的协议上实现较高级别的协议。该堆栈的哪一部分在用户库中或操作系统的一部分将因不同的操作系统而异。
对于我上面描述的假设设备,API 可能包含两个单字节阻塞调用,read()
并且write()
. 然后,您使用来自汇编程序或更高级别语言的某种系统调用机制来调用这些并传递参数/检索输出。在某些操作系统中,设备 I/O 可能看起来像文件 I/O,因此您将使用通用文件读/写来在设备上执行操作,并且操作系统会将这些操作分派给正确的设备驱动程序。此外,在典型的操作系统中,实际的系统调用将通过某种库提供,您可以再次从各种编程语言中调用这些库。