News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

need help with Linux asm code

Started by jack, August 02, 2024, 09:57:05 PM

Previous topic - Next topic

jack

for completeness here's my version without using rsp for storing the vendor id on the stack
I am sure that it could be simplified but for this exercise it's good enough
instead of using the stack I use the data at .m3 with 4 longs initialized to 0
sub cpuid naked cdecl
    asm
        .intel_syntax noprefix
            push    rbx
            push    rdx
            push    rcx
            mov     eax, 1
            sub     rsp, 16
            cpuid
            lea     rcx, .m0[rip]
            mov     edx, eax
            call    printf
            mov     eax, 0
            cpuid
            'place the vendor id in m3
            mov     dword ptr .m3[rip], ebx
            mov     dword ptr 4[.m3][rip], edx
            mov     dword ptr 8[.m3][rip], ecx
            mov     edx, eax
            lea     rcx, .m1[rip]
            call    printf
            lea     rdx, .m3[rip]
            lea     rcx, .m2[rip]
            call    printf
            lea     rcx, .m3[rip]
            add     rsp, 16
            pop     rcx
            pop     rdx
            pop     rbx

            ret
        .m0: .string "CPUID: %x\n"
        .m1: .string "Largest basic function number implemented: %i\n"
        .m2: .string "Vendor ID: %s\n"
        .data
        .m3: .fill 4, 4, 0
    end asm
end sub

cpuid

print "press return to exit"
Sleep

sinsi

With the original Windows code, does FreeBasic take care of aligning the stack and allocating spill/shadow space?
The Win64 ABI requires the first 32 bytes of the stack as spill space for the first 4 registers, and the called function "owns" this memory so if printf decides to use it your string gets trashed.

jack

sinsi
good question, I am inclined to think that it takes care of the alignment but am not sure
not reserving 32 bytes for the function call is sloppy/lazy on my part, if I understand it right, instead of sub rsp, 16 I should have used 32
in FreeBasic when writing naked functions you must take care of any memory, stack and registers
you can write regular [non-naked] functions much like you can in PowerBasic.

sinsi

Looking into FreeBasic's syntax, it seems that "naked" means no prologue/epilogue, so the stack isn't aligned.
Here is an untested proc - I'm unsure of FreeBasic and C calling conventions in Win64, I'm assuming it's fastcall
sub cpuid naked 'cdecl <== not sure about this, Win64 uses fastcall
    asm
        .intel_syntax noprefix

'on entry the stack is aligned 8, Win64 expects align 16
            push    rbx 'must save, this is non-volatile in Win64
            push    rdx 'not needed, this is volatile in Win64
            push    rcx 'not needed, this is volatile in Win64
'we need a minimum of 32 bytes shadow space, even if a function has fewer arguments
'an odd number of pushes will align the stack to 16
'we want an additional 16 bytes to store the vendor
    sub     rsp,32+16
'unchanged code
            mov     eax, 1
            'sub     rsp, 16
            cpuid
            lea     rcx, .m0[rip]
            mov     edx, eax
            call    printf
    mov     eax, 0
            cpuid
            'place the vendor id in m3
            'mov     dword ptr .m3[rip], ebx
            'mov     dword ptr 4[.m3][rip], edx
            'mov     dword ptr 8[.m3][rip], ecx
'put the vendor on the stack
    mov     [rsp+32],ebx
    mov     [rsp+36],edx
    mov     [rsp+40],ecx
    mov     byte ptr [rsp+44],0
            'unchanged code
            mov     edx, eax
            lea     rcx, .m1[rip]
            call    printf

            'lea     rdx, .m3[rip]
'the string is hopefully on the stack :)
    lea     rdx,[rsp+32]
            lea     rcx, .m2[rip]
            call    printf
    'lea     rcx, .m3[rip]

            add     rsp, 32+16
            pop     rcx
            pop     rdx
            pop     rbx

            ret
        .m0: .string "CPUID: %x\n"
        .m1: .string "Largest basic function number implemented: %i\n"
        .m2: .string "Vendor ID: %s\n"
        '.data
        '.m3: .fill 4, 4, 0
    end asm
end sub

cpuid

print "press return to exit"
Sleep

jack

thank you sinsi  :thumbsup:
after I had gone to bed and thinking about this, I realized why it was printing garbage when using the stack, it was being overwritten by printf, you reminded me of something that I had been reminded before but not taken to heart, reserve 32 bytes of stack for the external function being called
Quotean odd number of pushes will align the stack to 16
I didn't know that, thanks

this morning before I had seen your post I made some corrections but your corrections are complete, thank you  :biggrin:

jack

I searched the web for x64 stack alignment and I have come to the conclusion that programming in asm is a hassle that is not worth it, gcc and clang are very good at optimizing code
there are times when you need to do bit-fiddling and doing that in a HL is a hassle and ugly, some compilers have intrinsic functions to alleviate this

NoCforMe

If you could find a high-level language that uses the 32-bit ABI you'd find it a hell of a lot simpler. No stack hassles like with X64. Don't know what HLLs use that, though.
Assembly language programming should be fun. That's why I do it.