Question Details

No question body available.

Tags

c parsing assembly

Answers (3)

June 15, 2026 Score: 3 Rep: 27,615 Quality: Medium Completeness: 50%

You are correct that there is no need to parse text more than once.

No matter how many passes parsing text, an assembler will have to store symbols (e.g. labels) in a symbol table of some sort.  It should keep a list of unresolved locations, (forward or external) references associated with each symbol, so that:

  • forward references to symbols that are eventually defined can be fixed/patched
  • locations (line numbers) of symbols that are undefined can be reported in error messages
  • external references can have fixups / relocation generated into the output object file, which is how the linker addresses cross references.

Typically, such a list of locations requiring resolution has an addressing mode associated with it so you can have direct references (e.g. data to data) as well as a variety of executable references (code to code, perhaps as pc-relative or code to data, etc..), and the assembler then knows how to provide the proper patch, and/or communicate via generated relocations same to the linker.

June 15, 2026 Score: 2 Rep: 381,327 Quality: Medium Completeness: 80%

Yeah, the GNU assembler makes one pass over the source, only multiple passes over the parse result data-structures to fill in symbol references that weren't yet known when first seen. And for stuff like branch-displacement optimization (e.g. x86 jmp rel8 vs. jmp rel32). or e.g. x86 add edx, imm8 vs. add edx, imm32 when the source operand is a symbolic constant defined with a later .equ directive.

NASM is another open-source assembler you could look at, and is x86-specific so its internals might be simpler than the GNU assembler which has to target many different ISAs. It has a fairly-sophisticated macro preprocessor built-in, including support for macro looping for generating repetitive data or blocks of instructions with updating a macro value in each iteration. But that doesn't increase the number of passes through the source. It has things it calls "critical expressions" to prevent circular dependency chains for e.g. times n db 0, that can't depend on something that would change with the size of how that expands.

June 15, 2026 Score: 1 Rep: 166,346 Quality: Low Completeness: 20%

You've described a linker. In typical object-file formats, the object file contains a section with any labels that are defined in the object file, and any locations that reference labels that aren't locally defined. The linker then combines a set of object files into an executable, rewriting jump and call instructions to point at the correct location in the assembled binary.

A lot of "classical" compilation techniques are based around historical hardware platforms: the first assembler I used was on a system with 64 KiB RAM (and much of that hidden by mapped ROMs and I/O ports) and a 1 MHz clock. Starting around the turn of the millennium it started to be practical to compile and link a whole program in a single process. On anything even vaguely modern I wouldn't worry about your assembler requiring one pass or two to do name resolution.