views:

217

answers:

8

This sounds like a daft question at first, but bear with me.

It is common knowledge that binaries for one CPU architecture do not run on others. So for example it is impossible to run (without a compatibility layer of some kind), an x86 binary on a sparc64 chip. The instruction sets are different, so clearly that will not work.

But when the binary is for the same CPU, but for a different operating system, which part of the code prevents execution from being possible. For example, running an x86 Solaris binary on an x86 Linux box. I am assuming that there is some kind of platform specific stub which relates to the run-time linker or process scheduler?

I would be interested to know. Thanks.

+1  A: 

It is system specific libraries that are not always portable. For example, you cannot use the win32 window api on vanilla linux (and yes i realize there are work arrounds for this such as wine, its not the best example).

Cdsboy
+2  A: 

It's mainly the APIs. For example Win32 APIs are not really available on Linux. It is possible to get around this though, see Wine. The executable format may also be different (ELF/PE), but that could be fixed fairly easily (Wine does this; it allows PE executables to be executed on Linux).

Also, your example of Solaris and Linux executables mixing would be fairly easy to implement, since the OSs are so similar (ELF for executable format, POSIX APIs, X window system, etc.). FreeBSD can already run Linux executables. The reason this is not so common is simply that there is not much of a demand for it. There are a whole lot more Windows programs than *NIX programs, so Wine was created. There are a whole lot more Linux programs than FreeBSD programs, so FreeBSD implemented the Linux compatibility layer. Solaris might eventually implement something similar too. However, don't expect the reverse (Solaris/BSD executables on Linux), since there is just no demand for it.

Zifre
+1  A: 

System libraries and APIs. Actual simple code should work. This is why layers like Wine don't do any CPU emulation, they just re-implement the Windows API.

Etienne Perot
A: 

As has been already pointed out the incompatibility has less to do with the executable formats themselves then the libraries referenced by an executable.

I believe linux is actually compatible with a number of different executable formats although I could be wrong here

Crippledsmurf
+10  A: 

There are a number of reasons. The main ones, ordered in "distance from the metal" are:

  1. The operating systems may have different binary formats for executable files. In this case you will not be able to load the binary in the first place.
  2. The program may use another method to indicate they wish to place a system call (e.g. INT21 vs INT80).
  3. The program may rely on system calls that are not present in the other OS (e.g. dlopen())
  4. The program may rely on the standard library not present on the other OS.
  5. The program may rely on other libraries that are not available on the other OS.

Of course there are many more ways a program running in an unexpected environment can fail spectacularly.

Ranieri
Reasons 1, 2, and 3 are very easy to fix. Linux already supports a large number of executable formats. New interrupts could be created with a loadable kernel module. And system calls usually correspond pretty well between different OSs.
Zifre
I should have said we are assuming ELF :)Thanks for the answer.
vext01
+4  A: 

There are four problems:

  1. Different operating systems package their binary executables differently (eg Linux ELF vs Windows format);
  2. Different instruction sets on different CPU architectures;
  3. Different operating systems have different system calls (eg CreateProcess() in Win32 vs fork() in Linux/Unix);
  4. Differences such as paths, legal characters, directory separators and so on.

Non-system libraries are assumed to be present on both, otherwise that's another difference.

cletus
A: 

In addition to what others have said, the actual format of the executable may be different. So when the OS comes to load it, it doesn't find the values it is expecting for code, data segments etc. in the right places in the file.

anon
Again, that could be fixed fairly easily. Linux already supports many executable formats. Wine does this too. The libraries are a *much* bigger factor than executable format.
Zifre
+1  A: 

Besides binary format and other "packaging" features (which might not be exactly trivial either) There are also consequences that you find in nearly every code fragments. Stuff like

  1. PIC might cause every global access to rely on system specific assumptions on reloading the GOT pointer, and assumptions on additional offsets.
  2. Many systems have a specific ABI, passing small structs in registers, skipping registers for alignment purposes, reserving registers for special purposes Some have several (like ARM EABI and OABI)
  3. thread local storage related issues, variables that are instantiated per thread are tightly coupled to the facilities the OS specifies. Register choice, offsets etc.
  4. Some OSes (most notably) windows have support for a certain format of exception handling to allow cross-language and even cross-machine(via DCOM) exception handling.
  5. Higher level cross-program systems (like COM, but also e.g. Objective C interoperability on Mac, or compability with a certain KDE-gcc versioncombination) might also have certain requirements on VMT layout.
  6. Some linkers and formats support offsets negative to a section, some not.

Note that this is just a braindump of stuff that could be interesting to look into. It is probably not complete, and not all might apply. Some of the points above might overlap (e.g. reserving a register for TLS or PIC is also an ABI change)

Marco van de Voort