Я следую руководству по разработке ОС. Там мне нужно реализовать функцию, которая получает адрес (длиной 2 байта) порта ввода / вывода, данные (длиной 1 байт) для отправки на этот порт и отправляет данные на указанный порт.
Это должно быть реализовано в сборке (NASM) и использовано в коде C через определенный заголовок функции. Вот решения из учебника:
io.s
global outb ; make the label outb visible outside this file
; outb - send a byte to an I/O port
; stack: [esp + 8] the data byte
; [esp + 4] the I/O port
; [esp ] return address
outb:
mov al, [esp + 8] ; move the data to be sent into the al register
mov dx, [esp + 4] ; move the address of the I/O port into the dx register
out dx, al ; send the data to the I/O port
ret ; return to the calling function
io.h
#ifndef INCLUDE_IO_H
#define INCLUDE_IO_H
/** outb:
* Sends the given data to the given I/O port. Defined in io.s
*
* @param port The I/O port to send the data to
* @param data The data to send to the I/O port
*/
void outb(unsigned short port, unsigned char data);
#endif /* INCLUDE_IO_H */
Мой вопрос о этой части:
; stack: [esp + 8] the data byte
; [esp + 4] the I/O port
; [esp ] return address
Я строю для 32-битной среды, поэтому 4-байтовая разница между адресом return address
и адресом I/O port
имеет смысл - это из-за return address
длиной 4 байта. Но почему разница между адресами I/O port
и data byte
также равна 4?
Я подумал, что когда я вызываю функцию в C, она напрямую помещает аргументы в стек, затем отправляет адрес возврата и переходит функционировать (имеется в виду, что в моем понимании data byte
должно быть [esp + 6]
(4 байта return address
+ 2 байта I/O port
) вместо [esp + 8]
), но, похоже, он также выравнивает параметры по 4 байта границы, но я не уверен в этом.
Это происходит из-за флага -m32
? Я читал об этом флаге в документации по GNU, и в нем говорится:
-m32
-m64
Generate code for a 32 bit or 64 bit environment. The 32 bit environment sets int, long and
pointer to 32 bits. The 64 bit environment sets int to 32 bits and long and pointer to 64
bits.
Так что, похоже, это только меняет размеры int / long / pointers. Так почему сборочная сторона «уверена», что параметры будут на границе 4 байта? Это просто соглашение? И если да, то зачем это нужно?
Вот все флаги, которые я использую для сборки:
CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \
-nostartfiles -nodefaultlibs -Wall -Wextra -Werror
LDFLAGS = -T link.ld -melf_i386
ASFLAGS = -f elf32