简体   繁体   中英

What is the nasm assembly code version of gcc inline assembly

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM