What is the actual relation between assembly, machine code, bytecode, and opcode?
I have read most of the SO questions about assembly and machine code, such as this,
Briefly:
"Assembly" is what you feed through an "assembler". An assembler is a program which reads in several decks of punched cards and "assembles" them into a single program.
Or at least that used to be. Now the cards are replaced with disk files. But the data on the "cards" is a "machine language" which is the numeric values for the machine instructions.
But modern assemblers are SAPs -- Symbolic Assembler Programs -- so you can replace the numeric values with symbols -- say "LOD" for a Load instruction, "R1" for register 1, and "label5" for the instruction address 26734.
"Machine language" is the way that individual instructions (or "orders", if you're a Brit) to the CPU are represented. For a symbolic assembler you might have "LOD R1, LOOPCOUNT" to represent the instruction to load the value at the word labeled LOOPCOUNT into register 1. "LOD", by the way, is the "opcode" -- the (symbolic version of the) numeric value that tells the computer what to do next. (And note that every different computer design uses a different machine language, possibly with different symbols for the opcodes. Most of what you will find on the web is one version or another of the Intel machine language, but you would find, say, the IBM 370 to be radically different.)
"Bytecode" is a different sort of "machine language" which operates on a "virtual machine" instead of real hardware. The best known case of this is the Java Virtual Machine. "Bytecode" is a notation similar to regular "machine language" but idealized to an extent, since running on a virtual machine relieves it from some of the realities of a real hardware environment.