Suppose, I have a program written in C and I have two identical computers, the one is running Windows and the other is linux. Since the computers are identical, their processors have the same instruction set, so the machine code after compilation should be the same. So why do I need to compile my program twice? Suppose, I dont call any OS-related function, or something that depends on the actual OS.
Machine code does not depend on OS, it's same for the same CPU.
If you did OS agnostic piece of machine code, in target CPU mode (let's say x86 32b), and load that into some ROM memory, so it will be available, you can map that part of ROM both in Windows and in linux (by completely different OS API to map physical memory and give it executable rights), and jump there.. and the machine code in ROM would run the same way.
So why do I need to compile my program twice? Suppose, I dont call any OS-related function, or something that depends on the actual OS.
You don't have to. But usually you want some entry point into your code, and usually the simplest way how to provide universal entry point is to follow the OS defined ABI (Application Binary Interface), so for example in 32b windows you read arguments from stack, and in 64b linux you receive arguments in registers (when possible). If you wouldn't adjust your procedure prologue code to pick arguments in correct way, it will operate with wrong inputs in the "other" OS than it is written for.
But the machine code itself, the CPU instructions, are same.
That said, on x86 the situation is a bit more hairy due to historical backward compatibility, so the CPU can be in 16b mode, 32b [protected] mode (couple of them plus differently set up), or 64b mode. The 80386 CPU instruction mov eax,1
has different machine code encoding for 16b mode, and for 32b mode.
But as long as you are targetting the same CPU mode, the machine code of the same instruction is compiled in the same way. You just write source differently to follow different ABI.
And the executable files... each format is different, it's not even "per OS", again due to historical reasons almost all x86 OS support several executable file formats, so the meta data around machine code stored in the file (to be used by OS during loading machine code into memory and setting it up for run) are completely different.
Practical example is linux app wine
, which can execute windows executables, by providing fake OS hook points to simulate windows OS, and by understanding windows executable binaries, so correctly loading them into memory. The machine code of such windows application is run natively, without any further patching.
long
is 32 bits on x86-64 Windows, but 64-bits in the System V x86-64 ABI. So the same C struct can mean different things when compiled for different ABIs, not to mention single variables being different sizes (and thus needing different operand-size in the machine code, and different stack layout for locals, etc.) –
Abiosis syscall
or sysenter
or int 80h
based on CPU right. So why would depend on OS then? –
Dorcas syscall
as system call entry in x86_64, you can for example require every user app to call some absolute 64b address, etc... up to you as OS author to decide what is the convention on your OS. Up to SW authors to follow it, if they need OS call. IIRC all current x86 OS have some difference one way or another, even if using same instruction, the register-arguments ordering is different, etc. –
Perhaps syscall
, while windows may have identical functionality under "r12=34567" ("do_something"-like service) and rax=value, then syscall
. So you need almost identical, but different machine code for each OS, respecting different scheme for arguments passing. –
Perhaps © 2022 - 2024 — McMap. All rights reserved.