I understand how backpatching works during intermediate code generation, but I do not understand why it is needed.
A common argument for using backpatching during intermediate code generation is as follows:
Suppose the intermediate code generated is:
goto L1
...
L1:
When goto L1 is generated, the actual address of the target of goto is unknown. So we use a label L1 as a placeholder. When the code L1: is generated, we can backpatch the address where L1: is to goto L1.
However, why should we use the actual address for L1 during intermediate code generation? For example, LLVM IR uses symbolic labels in branch instructions instead of their actual addresses.
Even the RISC-V assembly language, which is often used as a targe language during targe code generation, uses symbolic labels in jump instructions. Isn't it the job of an assembler to replace labels with actual addresses?
The related post does not address my concerns above.