There are two main types of assemblers: one-pass and multi-pass assemblers. A two-pass assembler with an overlay structure can be used for small memory systems by separating the code and data for each pass. One-pass assemblers deal with forward references by either requiring data definitions come before uses or inserting undefined symbols into a table. Load-and-go one-pass assemblers generate code directly into memory. Multi-pass assemblers restrict forward references on the first pass and use linking to resolve them later.