I have this code which enables the cursor:
inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "d"(port) );
}
int main(void)
{
outb(0x3D4, 0x0A);
outb(0x3D5, (inb(0x3D5) & 0xC0) | 1);
outb(0x3D4, 0x0B);
outb(0x3D5, (inb(0x3D5) & 0xE0) | 2);
}
I want dont want to use inline assembly and wrote it in nasm assembly, however when using the assembly implementation of outb instead of inline assembly it wont enable the cursor correctly. The declaration for the nasm function:
extern void outb(uint16_t port, uint8_t val);
And the function:
outb:
mov dx, di
mov eax, esi
out dx, al
ret
Whats the problem?
Update: The function now looks like this but it still doesnt work:
outb:
push ebp
mov esp, ebp
mov dx, word [ebp+2]
mov al, byte [ebp+3]
out dx, al
mov esp, ebp
pop ebp
ret
Your code is correct for 64-bit SYSV ABI. Arguments are passed in EDI
and ESI
registers:
outb:
mov eax, esi
mov edx, edi
outb dx, al
ret
But in 32-bit ABI they're passed on stack :
outb:
mov edx, DWORD PTR [esp+4]
mov eax, DWORD PTR [esp+8]
outb dx, al
ret
But this also shows the problem with not using inline assembler - your arguments must now be pushed on stack and they must be popped too , whereas if you used the GCC inline assembly the compiler would just need to emit the outb
instructions inline interleaved with only stuff that places correct values into al
, dx
- and your code will be much more performant.
The NASM equivalent of static inline void...
is a macro , not a function you actually call
. The C compiler will inline it to a single out
instruction with the inputs in registers (or as an immediate, that's what the "N"
constraint allows, with "d"
allowing the DX register.)
Actually setting up a function call would be more trouble than just writing an out
instruction.
That macro should probably just be an out
instruction (no mov
overhead), with maybe %ifnidn
string processing and a %if
numeric condition to verify that the port number is the string dx
or a number from 0..255, and that the 2nd operand is al
. (See the manual for the limitations on the forms.)
Or just use out
directly like a normal person; in C the reason for wrapping it is to hide the inline-asm noise, but that doesn't apply in pure asm. Using a macro is more likely to just make things more difficult (by stepping on other registers if you don't limit it to just an out
instruction).
In NASM, the operand-size for out
is implied by the register you use: you can't write outb
, just out 0x80, al
or out 0x80, ax
or whatever. outb
is an error.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.