1

I'm trying to implement a C interface for processor's cpuid instruction. I'm aware that there are plenty of libraries for this and that using inline assembly for compilers that support it would be much simple, but I'm doing it this way because it just seems an interesting exercise to me. I'm assembling it using nasm in macho64 format:

; cpuid.nasm.x86_64.asm

global _cpuid

section .text
_cpuid:
    push    rax
    push    rbx
    push    rcx
    push    rdx

    mov     eax, [esp]
    mov     ebx, [esp+4]
    mov     ecx, [esp+8]
    mov     edx, [esp+12]

    cpuid

    pop     rax
    pop     rbx
    pop     rcx
    pop     rdx

    ret

section .data
// test.c

#include <stdio.h>
#include <stdint.h>


extern void 
cpuid(uint32_t *registers);


int
main(int argc, char **argv)
{
    uint32_t registers[4] = {0, 0, 0, 0};

    cpuid(registers);
}
nasm -f macho64 cpuid.nasm.x86_64.asm
gcc test.c cpuid.nasm.x86_64.o  
./a.out

However, when running the executable I get a segmentation fault. As far as I know seg. faults are caused by memory bad handling, but I cannot find any possible memory-related problem.

Peter Cordes
  • 286,368
  • 41
  • 520
  • 731
Giuppox
  • 1,236
  • 7
  • 30
  • 2
    The stack is LIFO. Pop in reverse order. (Though this does not explain the crash.) – Yves Daoust Feb 24 '22 at 16:42
  • FYI [There is already an intrinsic for this](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i386/cpuid.h) – Mgetz Feb 24 '22 at 16:42
  • 5
    You are using `esp` in 64-bit code. This may cause the problem. Use `rsp` instead of `esp`. – Martin Rosenau Feb 24 '22 at 16:42
  • 2
    The assembly expects 4 parameters. You are only passing one. But, regardless, you should be using a debugger. "I cannot find any possible memory-related problems." The debugger won't help you find _possible_ problems, it will help you find the actual problem. – Robᵩ Feb 24 '22 at 16:43
  • 1
    I thought x86_64 calling conventions used some registers before starting to push values to the stack. Besides, what system are you building for? – ndim Feb 24 '22 at 17:08
  • @YvesDaoust It was the problem, I fixed and it doesn't seg fault anymore. However it seems not to modify the value of the registers not – Giuppox Feb 24 '22 at 17:10
  • 1
    You are using gcc. Compile `test.c` with `--save-temps=obj` and take a look at the generated assembly file `test.s` to verify that the code generated from `test.c` can actually work together with your hand written assembly code. – ndim Feb 24 '22 at 17:18
  • 1
    @ndim: It does; the first arg is in RDI (non-Windows) or RCX (Windows). This code is broken in nearly every possible way, also including loading 4 args from the wrong place (or wrong number of levels of indirections / offsetting the wrong thing for array elements if you want to look at it that way), and overwriting all the CPUID *outputs* with push/pop, and not even trying to save the outputs back to the array. (EDX and EDX would be part of the 128-bit return value if you declared it as returning a struct or `__int128`, but even that wouldn't help with the EBX and ECX results.) – Peter Cordes Feb 24 '22 at 21:46
  • @PeterCordes I'm pretty new to assembly, would you provide an example of implementation? – Giuppox Feb 24 '22 at 22:09
  • Something like this compiler output: https://godbolt.org/z/GcrqPrTM8. GCC inlines its cpuid.h functions ([How do I call "cpuid" in Linux?](https://stackoverflow.com/q/14266772)) resulting in an asm function that runs CPUID and returns the results. – Peter Cordes Feb 25 '22 at 00:56
  • 1
    That doesn't handle using ECX as another input for some CPUID levels, and is cluttered by checking that that CPUID level is even supported, but in terms of calling convention / interacting with the pointer arg it should be clear. It's GAS Intel syntax, but trivial to translate to NASM (just remove the "dword ptr" stuff). See also https://wiki.osdev.org/CPUID for other simple functions you can compile. Or just generally [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) for more about getting compilers to make useful examples. – Peter Cordes Feb 25 '22 at 01:06

0 Answers0