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

hi all  :smiley:
on this page of the Wikipedia https://en.wikipedia.org/wiki/CPUID#Calling_CPUID if you scroll down a bit, you will see a small asm program to print 3 pieces of information about your CPU
I know that Linux and Windows use the CPU registers differently, how would you modify the program so that it would run on Windows ?
the reason I post in the Soap Box is because I don't program in masm but prefer high level languages, such as FreeBasic, the code below modified a bit as inline-asm works OK in Linux, it prints
QuotePUID: 906ed
Largest basic function number implemented: 22
Vendor ID: GenuineIntel

here's the FreeBasic code with inline-asm
sub cpuid naked cdecl
asm
.intel_syntax noprefix
' .text
'.m0: .string "CPUID: %x\n"
'.m1: .string "Largest basic function number implemented: %i\n"
'.m2: .string "Vendor ID: %s\n"

'.globl main

'main:

push    r12
mov     eax, 1
sub     rsp, 16
cpuid
lea     rdi, .m0[rip]
mov     esi, eax
call printf
mov     eax, 0
cpuid
lea     rdi, .m1[rip]
mov     esi, eax
mov     r12d, edx
mov     ebp, ecx
call    printf
mov     3[rsp], ebx
lea     rsi, 3[rsp]
lea     rdi, .m2[rip]
mov     7[rsp], r12d
mov     11[rsp], ebp
call printf
add     rsp, 16
pop     r12

ret
'.text
.m0: .string "CPUID: %x\n"
.m1: .string "Largest basic function number implemented: %i\n"
.m2: .string "Vendor ID: %s\n"
'.section .note.GNU-stack,"",@progbits
end asm
end sub


cpuid

print "press return to exit"
Sleep

thanks in advance

jack

I almost got it, it prints
QuoteCPUID: 906ed
Largest basic function number implemented: 22
Vendor ID: -ö⌂
press return to exit
I can't figure out how to get the Vendor ID to work

sub cpuid naked cdecl
asm
.intel_syntax noprefix
' .text
'.m0: .string "CPUID: %x\n"
'.m1: .string "Largest basic function number implemented: %i\n"
'.m2: .string "Vendor ID: %s\n"

'.globl main

'main:

push    r8
push r9
push rbx
push rdx
push rsi
mov     eax, 1
sub     rsp, 16
cpuid
lea     rcx, .m0[rip]
mov     edx, eax
call printf
mov     eax, 0
cpuid
lea     rcx, .m1[rip]
mov esi, edx
mov     edx, eax
mov     r8d, esi
mov     r9d, ecx
call    printf
mov     3[rsp], ebx
lea     rdx, 3[rsp]
lea     rcx, .m2[rip]
mov     7[rsp], r8d
mov     11[rsp], r9d
call printf
add     rsp, 16
pop rsi
pop rdx
pop rbx
pop r9
pop     r8

ret
'.text
.m0: .string "CPUID: %x\n"
.m1: .string "Largest basic function number implemented: %i\n"
.m2: .string "Vendor ID: %s\n"
'.section .note.GNU-stack,"",@progbits
end asm
end sub


cpuid

print "press return to exit"
Sleep

NoCforMe

Here's my code for displaying the vendor ID using CUPID:

$CRLF EQU <13, 10>
$tab EQU 9

VendorIDstring DB $CRLF, "Vendor ID:", $tab, $tab, '"'
VendorID1 DB "xxxx"
VendorID2 DB "xxxx"
VendorID3 DB "xxxx"
DB '"', $CRLF, 0

; CPUID w/EAX=0--get vendor ID string:
XOR EAX, EAX
CPUID
MOV DWORD PTR VendorID1, EBX
MOV DWORD PTR VendorID2, EDX
MOV DWORD PTR VendorID3, ECX

; Now you can output the entire string (VendorIDstring) by your chosen method.

The ID string comes back in 3 registers (EBX, ECX, EDX) as 12 bytes of data. It's not a string.

You can adapt this code to yours. Also no need to use 64-bit anything in this.
Assembly language programming should be fun. That's why I do it.

jack

thank you NoCforMe
the code in opening post works ok in Linux, why doesn't the second post work in Windows ?
if I hard-code the numbers that EBX, EDX and ECX return from CPUID in the data section then it prints "Vendor ID: GenuineIntel"
but if I place the values on the stack [rsp] it prints garbage
here's the hard-coded version, the values placed on the stack are irrelevant in this case
sub cpuid naked cdecl
asm
.intel_syntax noprefix
push    r8
push r9
push rbx
push rdx
push rsi
mov     eax, 1
sub     rsp, 16
cpuid
lea     rcx, .m0[rip]
mov     edx, eax
call printf
mov     eax, 0
cpuid
lea     rcx, .m1[rip]
mov esi, edx
mov     edx, eax
mov     r8d, esi
mov     r9d, ecx
call    printf
mov     dword ptr 3[rsp], 1970169159
mov     dword ptr 7[rsp], 1231384169
mov     dword ptr 11[rsp], 1818588270
'lea     rdx, 3[rsp]
lea rdx, .id[rip]
lea     rcx, .m2[rip]
call printf
add     rsp, 16
pop rsi
pop rdx
pop rbx
pop r9
pop     r8

ret
.id: .long 1970169159, 1231384169, 1818588270, 0
.m0: .string "CPUID: %x\n"
.m1: .string "Largest basic function number implemented: %i\n"
.m2: .string "Vendor ID: %s\n"
end asm
end sub

cpuid

print "press return to exit"
Sleep
but on Windows I could simply call the function __cpuid provided by MS

my beef is, why doesn't it work when the values are placed on the stack?

NoCforMe

Quote from: jack on August 04, 2024, 04:10:56 AMmy beef is, why doesn't it work when the values are placed on the stack?
Well, you're using this inside a FreeBasic program, correct? So it's a FreeBasic thing.

One thing I really don't like here are those weird odd-numbered stack offsets:
            mov    7[rsp], r8d
            mov    11[rsp], r9d

Are those really correct? I know nothing about how FreeBasic handles stack allocation. That seems to be the source of your troubles.
Assembly language programming should be fun. That's why I do it.

jack

I agree, the odd offsets look wrong, but that is what is on the Wikipedia
anyway, I let this rest, it just bugs me not knowing what the problem is with the stack

jack

I think I know why the Wiki use these odd offsets, it's so that the string will have terminating 0

NoCforMe

Hmm, that doesn't make sense to me; the terminating 0 would be at the end, so how would adjusting the offset (the beginning of the string) affect that?

Do you know how FreeBasic sets up its stack frame? That info should be available, and might help you figure out what's actually happening in that code.
Assembly language programming should be fun. That's why I do it.

jj2007

FreeBasic uses the BSTR format for strings. The DWORD before the string start is the length.

NoCforMe

Aha; so .string inserts that DWORD first, then the string data.
So in order to use such strings with standard (ASCIIZ) string functions, you need to point past the first 4 bytes of each string, correct?
Assembly language programming should be fun. That's why I do it.

jack

@NoCforMe
in this inline-asm example no FreeBasic strings or functions are used, it simply calls the C printf function which expects a 0 terminated string

NoCforMe

Is .string a FreeBasic macro or operator? If so, it may be putting a length word before the string text.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on August 04, 2024, 08:05:40 AMyou need to point past the first 4 bytes of each string

IIRC FB returns a ptr to the start of the string, not to the length DWORD

jack

the .string is a gnu assembler directive to include a string into the object file, see .string
FreeBasic uses the gnu assembler and linker to produce it's executables
when you use inline asm you can use these directives in your source, there are probably some directives that are not applicable for use in inline asm

NoCforMe

Quote from: jack on August 04, 2024, 11:01:48 AMthe .string is a gnu assembler directive to include a string into the object file, see .string

OK; it creates an ASCIIZ string, not a BSTR.
Assembly language programming should be fun. That's why I do it.