As you may have guessed, executable formats contain more than just machine code. For example, they can:
- Specify metadata for the OS, e.g. which architecture the executable is intended for. This metadata comprises the header of the file.
Specify the program layout in memory. On modern OSes, most executable are not loaded into memory in a single chunk - they usually have many separate regions/sections/segments. Some of these segments will contain executable code. Some of them will contain immutable data, like text strings. Some of them will be designated as writable memory, for the program heap(s).
Different programs will have different requirements (requests) for the sizes of these sections. This is all specified in the header.
Some formats will also allow you to embed a digital signature, which allows verification of where the binary came from.
- Why a separate specification is needed for the binary code - Linux uses ELF and Windows uses Portable Executable Format?
The reasons are primarily historical, and OSes tend to stick with their existing 'native' (or 'default') format unless there is compelling reason to switch (as has happened e.g. from the DOS MZ format to PE in NT 3.1, and from a.out to ELF in Linux 1.2, and from COFF to ELF in various Unixes over the years).
It should be noted that the underlying machine code depends on the CPU architecture but is otherwise (syscalls and linked libraries aside) largely portable between OSes. In fact, modern Windows and Linux can run both executable formats: ELF executables will run on Windows via WSL, and PE executables will run on Linux via WINE.
- Can an operating system and a program that runs on that operating system be created without this binary format specification?
We go back to the primary purpose of these formats. Without the metadata telling the OS where to load parts of the program, most modern executables cannot run. Some very old formats like COM pretty much contain pure code, but are not particularly flexible and have fallen out of favour.
In practice, there is no need for an operating system to even exist. At the hardware level, assuming the existence of a (legacy) BIOS, the BIOS will simply start executing at a specific location on the disk (MBR), which can be arbitrary machine code that then takes over and either starts an OS or does anything else it likes. (You could view the MBR itself as a binary format, though it is not directly related to the executable code.) The more modern UEFI, however, does specify a more complex executable format (PE).
- Is the binary format architecture dependent, OS dependent or both?
Depends on the format, really. Some formats assume a specific architecture. Others allow you to select the architecture from a list of specified "magic numbers" in the header. Still others are completely architecture-agnostic (e.g. Java and .NET/CIL bytecode).
Similarly, the format generally imposes no restriction on the OS, though the OS will be restricted in which formats it can (natively) recognise and execute. Of course, compatibility layers on top of the core OS can execute other formats (e.g. JVM, .NET/CLR, WSL&WINE, etc.) that the core OS may not recognise.
- Does binary format applicable to only executable files or it is applicable to the operating system code as well?
A large portion of most modern operating systems is just a collection of "normal" executable files. However, some parts of the operating system are "special" and will not necessarily use the same format as the rest. Usually, this applies to just the bootloader and kernel.
To pull a specific, very common, example, the legacy BIOS bootloader will not be in either the ELF or PE formats used by Linux and Windows. The Linux kernel is generally built in an ELF-derived format that the GRUB bootloader can load, but it could be in a different format to be compatible with the bootloader used. The Linux kernel also supports an EFI Stub mode, which contains a minimal PE/COFF header to be compatible with direct UEFI boot.