Assembly Language Study Notes

Assembly Language Overview

  • Assembly language is defined as a textual representation of machine instructions.

  • Before building a processor, understanding the semantics of various machine instructions is fundamental.

  • Assembly languages are ISA- (Instruction Set Architecture) specific and compiler framework specific; thus, many variants exist.

  • This chapter aims to discuss the principles of assembly languages, provide a rigorous overview, and design a new assembly language (SimpleRisc).

Chapter Structure

  • Section 3.1: The need for assembly language from both software developers' and hardware designers' perspectives.

  • Section 3.2: Discuss the generic semantics of assembly languages.

  • Section 3.3: Design SimpleRisc assembly language and encoding methods.

  • Chapters 4 & 5: Detail ARM and x86 assembly languages, respectively.

3.1 Why Assembly Language

3.1.1 Software Developer’s Perspective

  • Humans understand natural languages (e.g., English, Russian) and can learn programming languages (e.g., C, Java).

  • Computers operate on binary (zeros and ones) and cannot understand human languages directly.

    • Historical context: Early programmers manually turned switches corresponding to binary states (0 and 1).

  • Today's programming demands automatic conversion of high-level languages to machine code through compilers.

Definition 24
  • High Level Programming Language: Complex constructs/languages like C or Java, where each statement corresponds to many machine instructions and is independent of the processor's ISA.

  • Compiler: An executable program that converts high-level programming into machine code (sequence of zeros and ones).

  • Figure 3.1: Illustrates the compilation process where high-level code is transformed into machine code.

Trivia 1: History of Compilers
  • The original compiler needed a compiler to compile itself, creating a "chicken and egg" conundrum. Early programmers first created simple machine instruction-based compilers and subsequently advanced to high-level language compilers.

  • Modern development uses cross-compilers, which run on one machine and produce executable code for a different machine with potentially different ISAs.

    • Definition 25: Cross-Compiler – A program running on system A generating code for system B.

  • Despite the effectiveness of compilers, certain scenarios necessitate manual embedding of machine instructions in programs for efficiency or functionality.

  • Compilers face limitations in optimizing machine code due to constraints on algorithm efficiency and lack of awareness of broader code patterns.

  • Some instructions (added by processor vendors) may not be utilized by generic compilers, necessitating manual inclusion by system programmers.

Definition 26
  • Assembly Language: A low-level programming language with statements that each correspond to a single machine instruction, easing programmer's burden of memorizing binary sequences.

  • Assembly languages have a structured format consisting of instructions and operands, generally enabling the embedding of assembly within high-level languages and maintaining close control over hardware.

Definition 27
  • Assembler: An executable program that converts assembly language code into machine code.

Examples of Assembly Language Use
  • Example 20: High-performance 3D games require speed optimization, leading programmers to write assembly code for performance gains.

  • Example 21: In high-performance atom structure computing, assembly code writing significantly accelerated execution speed on supercomputers, as demonstrated by various studies.

3.1.2 Hardware Designer’s Perspective

  • Hardware designers focus on designing processors that implement instructions following the ISA effectively, considering efficiency in area, power, and complexity.

  • They depend on the assembly language for an understanding of what to build and how to translate instructions into hardware designs.

3.2 The Basics of Assembly Language

3.2.1 Machine Model

  • Revisiting the Harvard and Von Neumann architecture, assembly languages do not distinguish instruction and data memories, following an abstract Von Neumann machine model enhanced with registers.

  • The CPU reads and executes program instructions stored in main memory, and the Program Counter (PC) keeps track of the currently executing instruction.

CPU Components
  • Registers: Store input operands; most CPUs have fewer than 64 registers, with operations potentially sourcing from either registers or memory.

  • The CPU coordinates memory transfers, performs arithmetic and logical computations, and manages external I/O devices.

3.2.2 View of Memory

  • Memory, as an array of bytes, is indexed uniquely by addresses starting from 0.

  • Different data types in programming languages necessitate multimemory representations, implying that multibyte types require specified byte allocations.

Little Endian and Big Endian Representations
  • Little Endian: Stores least significant byte first.

  • Big Endian: Stores most significant byte first.

  • Example 22: With integer 0x87654321, the big and little endian representations would differ based on which byte is physically stored first in memory locations.

  • ARM processors can operate in bi-endian mode, while x86 traditionally uses little endian, and others like IBM POWER use big endian formats.

Arrays Representation
  • Arrays are sequences of memory locations, stored contiguously in one dimension, with an index mapping from multi-dimensional arrays to a single-dimensional structure.

Definition 28
  • Row Major Representation: Storing arrays row-wise in memory.

  • Column Major Representation: Storing arrays column-wise in memory.

3.2.3 Assembly Language Syntax

  • The syntax of assembly language depends on the assembler, with GNU assembler syntax covered.

  • An assembly file, a regular text file, typically has a .s file extension, which can be generated from C programs using a command-line interface integrated with the GCC.