-3

So since I am learning assembly and difference CPU types use different features or registers differently. Is there a way to be able to code and tell the difference between ARM,Intel, or AMD processors?

I have been researching and haven't found anything.

EDIT: The Purpose of this question was to determine that we would be creating assembly code for all platforms and if they would run based on the CPU and architecture alone rather than having to create seperate builds for each to make it easier. Although from the comments it seems you develop for each platform seperately

MATOS
  • 3
  • 2
  • 2
    If you don't know the CPU, how would you know which assembly language to write this CPU-detecting code in? – Scott Hunter Mar 31 '23 at 14:36
  • 3
    Machine code only works on the architecture it was written for. Writing e.g. x86-64 code excludes ARM processors. However, within one architecture, there can be multiple CPU vendors. You can some times distinguish them with special instructions. For example, x86-64 has the `cpuid` instruction for this. – fuz Mar 31 '23 at 15:04
  • 2
    @fuz: https://news.ycombinator.com/item?id=27033330 is 4-way polyglot machine code that detects x86 vs. ARM vs. AArch64 vs. MIPS(little endian). See also [Is it possible to compile a binary which will run on both x86 and ARM](https://stackoverflow.com/a/72947388) and [x86-32 / x86-64 polyglot machine-code fragment that detects 64bit mode at run-time?](https://stackoverflow.com/q/38063529) – Peter Cordes Mar 31 '23 at 17:57
  • 1
    @PeterCordes This is not best practise and I do not want to recommend anything like that to beginners. They'll think that this is how things are done. – fuz Mar 31 '23 at 18:02
  • arm uses something called cpuid as well I believe but it is a series of registers used to detect the features of the core as well as what core is this. – old_timer Apr 02 '23 at 11:43

1 Answers1

3

The key words to look for would be "CPU detection" or "CPU identification".

For distinguishing between architectures, like ARM vs Intel (x86), the question is moot. At the level of assembly, you had to pick an architecture to decide what instructions to code in the first place. For instance, if you wanted to add two numbers, did you write add eax, ebx (assembling to the bytes 01 d8), or did you write add x0, x1, x2 (assembling to 20 00 02 8b)? In the former case, you're writing for x86. In order to get to your supposed architecture detection code in the first place, you had to execute a lot of previous instructions that would only run on x86, so by the time you get there, you already know the answer. In the latter case you're writing for ARM (ARM64).

(Technically the same sequence of bytes will do something on both architectures; but on the other one, it surely won't be what you want. Usually the assembler/linker would tag your executable with the correct architecture, and if it doesn't match the machine where it's being run, the operating system will refuse to execute it.)

For distinguishing between CPUs of the same architecture, you first have to decide which architecture that is, as the methods will likely be very different. Very generally, there is usually some special instruction which returns information about the CPU. On x86 you mainly use cpuid, on ARM64 there are various system registers accessed with mrs, and so on. For how they work, and how to interpret the results, you have to consult the instruction set reference for that architecture.

For x86 in particular, there have been so many different x86 CPUs released over the years (between Intel, AMD, and other now-defunct competitors) that detection can be very complicated, depending how far back you want to go. (For instance, the cpuid instruction hasn't always existed, so the issue distinguishing between older CPUs, say pre-2000, could fill a long article.) Nowadays, there's the extra issue that your program may not even be running on x86 hardware, but may instead be in a VM with some other CPU that emulates x86.

For most purposes, the general question of "how do I tell which kind of CPU" is not really the right question to ask. Rather, identify the particular CPU feature you are interested in using (e.g. AVX instructions, enhanced rep movsb, etc), and then ask "how do I tell whether this CPU supports it"? Then usually there is a simple answer, e.g. "load 0x1234 into eax, execute CPUID, and check bit 7 of ecx" (made up example). Beyond that, there's no point in writing a lot of code to tell the difference between a Brandy Lake i8-1234U at 2035 MHz or a Vodka Lake i9-9876Z at 3107 MHz; in principle you could find out which one you are running on, but as a programmer you have no actual reason to care.

ecm
  • 2,583
  • 4
  • 21
  • 29
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • "Brandy Lake i8-1234U at 2035 MHz or a Vodka Lake i9-9876Z at 3107 MHz" I take it these are made-up architectures :-) – Sep Roland Mar 31 '23 at 17:29
  • 1
    Polyglot machine code is possible, see [Is it possible to compile a binary which will run on both x86 and ARM](https://stackoverflow.com/a/72947388) and [x86-32 / x86-64 polyglot machine-code fragment that detects 64bit mode at run-time?](https://stackoverflow.com/q/38063529) . Normally there's no need for that, of course; modern systems only load binaries with the right executable metadata. But hand-crafted machine code *can* do something useful on multiple different architectures. – Peter Cordes Mar 31 '23 at 18:02
  • @SepRoland: Well, between Whiskey Lake, Coffee Lake, Ice Lake, and Skyylake [sic], the "lakes" have got most of a cocktail bar already, so I'm sure these are among the natural successors. I guess you could throw in Amber (fluid) Lake, (Bombay) Sapphire Rapids, (Bacardi) Goldmont... – Nate Eldredge Apr 01 '23 at 05:22
  • 1
    @PeterCordes: True. So, readers should assume every sentence in my post carries an implicit "unless you are doing some kind of ludicrous hackery" :-) – Nate Eldredge Apr 01 '23 at 05:24