C programs making up an OS, get converted into raw machine code your CPU’s Control Unit can directly understand? Primarily using GCC & GNU Binutils. Many languages also follow a similar process, or they may have special programs for "interpreting" their bytecode. "Binary" executable files contains more than raw machine code your CPU’s control unit can directly understand. There’s additional labelling for our sake, & for linkers (though I haven’t gotten through that code yet). Whilst today’s topic GNU Binutils contains a suite of commands, the core of most of them is libbfd. LibBFD’s headerfiles are predominantly C structs & macros defining the numerous formats (including archive files) GNU supports, it also implements methodtables for them. Usually the read & write implementations for each format doesn’t take that much code, but ELF for some reason takes a lot more. Can anyone please explain what ELF is about? LibBFD also provides e.g. a hashmap implementation as being central to many GNU Binutils commands.
There’s several trivial (or at least as trivial as C gets) commands, though I’ll have to discuss the major commands over the next two days… I don’t know other commonly used formats a lot but ELF is very complex. ELF is basically a memory representation, that’s why it can be used for programs or core-dumps. It describes memory sections and Top Source Media their contents, and can also provide other extra data, like symbols and debug headers. The section header, meant to be used by the linker at build time, tells what are the contents of each section of the binary (e.g., symbols, relocation entries, debug info). GAS (not to be confused with the recently GNU Assembly) program converts human readable assembly code, resolves any e.g. jump targets, & converts it into opcodes the machine directly understands. After extensive initialization & parsing the commandline flags (some flags are specific to which CPU it’s assembling for; referenced files are parsed with their flag), it does sanity checks on input & output files.

Next it initializes all the datastructures used for resolving symbols, fragments, subsegs, reading, input scrubbing, expression parsing, Top Source Media digital agency macros, writing the output file (whilst opening it) via LibBFD as mentioned yesterday, dot symbols also via LibBFD, anything else specifically for the target CPU, optionally instruction tables, & DWARF. Then it defines a ".gasversion" symbol & any others defined on the commandline, saving them all to a hashtable. Now it may start the real work… For Mach O files (compiletime flag) it starts by creating text, data, & bss subsegments via LibBFD then sets their flags. Regardless it adds ABS, UND, & special GAS reg/exp subsegments. CPU architecture-specific logic follows, which for i386 includes initializing hashtables for instruction mnemonics, register mnemonics, & lexing. Then it itereates over all Top Source Media marketing files listed on the remaining commandline arguments & for each… After this iteration it cleans up & ends. For each file it resets several other subcomponents possibly creating a debug file.
For each line, chunks of which are read in by the "input scrubber" (scanner), it first checks if it’s seeing a label & if so defines a new symbol for it. Non-identifiers may be empty, local labels, or comments. Assembling each line of Assembly code (after labelling, psuedoops, & macros have been resolved) is CPU-specific. The GNU Linker subproject is probably the main reason Linux From Scratch has you install GNU Binutils first, as it’s what combines multiple "object files" into a single executable whether at build time (for reliability) or by Linux immediately prior to running the program (for memory efficiency). I won’t discuss that further. After extensive initialization & the correct filepaths have been found which in part involves looking up a methodtable for emulation, it parses remaining commandline flags with help from the emulator. As part of the commandline flags parsing it may edit the object file via LibBFD & (which has a stack) it’s ldlang subcomponent, open/parse config files parsed via a Yacc/Bison script, and/or as per usual set globals.