1

Is it possible to check the CPU architecture(is 64 or 32 bits) in a x86/x86-64 CPU without gathering information from the OS or some API, by means of low level code (C/C++ or assembly)?

One could check for the size of a pointer, like discussed here, but, from what I understand, this way lets you know the OS architecture is compiled for, because a 64 bit CPU running a 32 bit OS would report wrong results.

Maybe some cpuid instruction or similar could do the trick but I couldn't find anything that fully satisfies these requirements. If you think it's not possible, I would appreciate a good reason to justify this (this may be a less objective answer). If you are wondering, this is for a CPU detection software.

Edit: In Determine 32/64 bit architecture in assembly, OP does not get some specific answer that explain how to do it, just that you should use cpuid, and links to How do you detect the CPU architecture type during run-time with GCC and inline asm?, that shows a good answer to me, but it isn't as complete as the answer that I marked as accepted, because Remy Lebeau gives a detailed explanation and tells which specific cpuid bit must be queried, instead of just writing some code, and I find it more appropiate for my question, because it is explained at a higher level scope(I never mentioned gcc, the second post does)

DrNoob
  • 75
  • 1
  • 7
  • 1
    If you compile your executable for 64bit, the CPU must be 64bit. But if you compile your executable for 32bit, the CPU may be 32bit or 64bit (if a 32bit emulator is installed, like WOW64 on Windows), so you MUST query the hardware details to differentiate. Best to get that from the OS, but the `CPUID` instruction does have a ["Processor Info and Feature Bits"](https://en.wikipedia.org/wiki/CPUID#EAX=1:_Processor_Info_and_Feature_Bits) query (look at the `ia64` feature flag in particular on Intel CPUs). – Remy Lebeau Jun 21 '18 at 22:21
  • 3
    Are you asking about x86 / x86-64 in particular, or 32/64-bit processors in general? (I'm not sure there is a general answer.) – prl Jun 21 '18 at 22:26
  • Isn't this the tail wagging the dog? The code is compiled for a particular architecture. – Weather Vane Jun 21 '18 at 22:34
  • Or the `long mode` bit from the ["Extended Processor Info and Feature Bits"](https://en.wikipedia.org/wiki/CPUID#EAX=80000001h:_Extended_Processor_Info_and_Feature_Bits) query on AMD CPUs. – Remy Lebeau Jun 21 '18 at 22:34
  • @Remy Lebeau You assume that we deal with x86 here only, don't you? What about others like ARM? – Michael Beer Jun 21 '18 at 22:34
  • I doubt there exists a general approach. The C standard does not provide for a mechanism at least. Assembly can only be used if you already assume a certain target architecture... – Michael Beer Jun 21 '18 at 22:36
  • 1
    You also do not define what OS you assume. Under Linux, the changes are high that you find the appropriate information in the `/proc` (look at the content of `/proc/cpuinfo`) or the `/sys` file system. – Michael Beer Jun 21 '18 at 22:38
  • 1
    For the **general** case, this is impossible; I've tried at length. The best you can do is write a bunch of hard-coded Triple->{various pieces of information} tables, but even this won't save you from GCC's ./configure flags or `-m` options. If you have constraints, list them. – o11c Jun 21 '18 at 22:38
  • @MichaelBeer ARM doesn't have a `CPUID` instruction like Intel/AMD do, but it does have a [`CPUID` register](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0395b/CIHCAGHH.html) instead. – Remy Lebeau Jun 21 '18 at 22:41
  • @Remy Lebeau: This sounds like it would make sense to forge an answer out of your comments, wouldn't it ;) – Michael Beer Jun 21 '18 at 22:46
  • There is nothing in the `C++` standard for it and not every `CPU` is bound to report itself with exactly the same code so I think you are stuck with querying the operating system. – Galik Jun 21 '18 at 22:48
  • @MichaelBeer done – Remy Lebeau Jun 21 '18 at 22:56
  • RemyLebeau zx485 Looks good but I need time to check it out. Specially, really liked your approach, RemyLebeau. MichaelBeer I don't define a OS because I was looking for a non OS dependent solution. prl I'm sorry, I have edited the post to clarify that. Thank you all for your comments, need time to test some of your ideas. – DrNoob Jun 21 '18 at 22:56
  • What do you want to do with this information? Do you want to create a 32-bit executable that checks whether a 64-bit executable could run on the current OS? Or are you writing a kernel that checks if it can switch to 64-bit mode after booting as far as 32-bit mode? – Peter Cordes Jun 21 '18 at 23:06

2 Answers2

6

It is possible to write code for x86 that runs in either 32- or 64-bit mode. If you are running such code, you can check which mode you are in with the following:

get_mode:
        mov eax, 1
        dec eax
        test eax, eax
        ret

In 64-bit mode, dec eax becomes the REX.W prefix for the test instruction. Thus, this code returns 0 when run in 32-bit mode and returns 1 when run in 64-bit mode. It also sets Z accordingly, so it can be used from another assembly language function like this:

        call get_mode
        jnz mode64
prl
  • 11,716
  • 2
  • 13
  • 31
  • 2
    Does this answer the question of the OP? Form what the OP says about checking the size of a pointer, I guess the OP is not interested in the current operation mode of the CPU, but the basic abilities of the CPU? – Michael Beer Jun 21 '18 at 22:44
  • It's legal to put a REX prefix on a `jcc`, so you can do better than that: [x86-32 / x86-64 polyglot machine-code fragment that detects 64bit mode at run-time?](https://stackoverflow.com/q/38063529). See also my code-golf [Determine your language's version](https://codegolf.stackexchange.com/a/139717) which is a callable function that returns 16, 32, or 64 for the current mode. – Peter Cordes Jun 21 '18 at 23:20
  • @Michael, you're right that this may not answer the question, which OP hasn't clarified, despite all the comments. But I felt this *might* answer his question and I thought it would be interesting to anyone who hasn't seen it. (Of course I could have guessed that Peter had already written it.) – prl Jun 21 '18 at 23:38
5

If you compile your executable for 64bit, the CPU must be 64bit only.

If you compile your executable for 32bit, the CPU may be 32bit or 64bit (if a 64bit CPU is capable of running 32bit code), so you MUST query the CPU to differentiate. Best to get that from the OS when possible, but the CPU may have its own query for that info.

For instance, on an x86 or x86-64 CPU, there is a CPUID instruction available:

CPUID has a "Get vendor ID" query to determine the CPU manufacturer.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    But if your x86-64 CPU is running a 32-bit OS, it still won't be able to run a 64-bit executable. So it's pretty much not useful to detect this CPU capability which the OS won't let you take advantage of. – Peter Cordes Jun 22 '18 at 02:37