x86 MASM Chapter 7

Chapter 7: Integer Arithmetic

Chapter Outline

  • Shift and Rotate Instructions

    • 7.1

    • 7.1.1 Logical Shifts and Arithmetic Shifts

    • 7.1.2 SHL Instruction

    • 7.1.3 SHR Instruction

    • 7.1.4 SAL and SAR Instructions

    • 7.1.5 ROL Instruction

    • 7.1.6 ROR Instruction

    • 7.1.7 RCL and RCR Instructions

    • 7.1.8 Signed Overflow

    • 7.1.9 SHLD/SHRD Instructions

    • 7.1.10 Section Review

  • Shift and Rotate Applications

    • 7.2

    • 7.2.1 Shifting Multiple Doublewords

    • 7.2.2 Multiplication by Shifting Bits

    • 7.2.3 Displaying Binary Bits

    • 7.2.4 Extracting File Date Fields

    • 7.2.5 Section Review

  • Multiplication and Division Instructions

    • 7.3

    • 7.3.1 Unsigned Integer Multiplication (MUL)

    • 7.3.2 Signed Integer Multiplication (IMUL)

    • 7.3.3 Unsigned Integer Division (DIV)

    • 7.3.4 Signed Integer Division (IDIV)

    • 7.3.5 Implementing Arithmetic Expressions

    • 7.3.6 Section Review

  • Extended Addition and Subtraction

    • 7.4

    • 7.4.1 ADC Instruction

    • 7.4.2 Extended Addition Example

    • 7.4.3 SBB Instruction

    • 7.4.4 Section Review

  • ASCII and Unpacked Decimal Arithmetic

    • 7.5

    • 7.5.1 AAA Instruction

    • 7.5.2 AAS Instruction

    • 7.5.3 AAM Instruction

    • 7.5.4 AAD Instruction

    • 7.5.5 Section Review

  • Packed Decimal Arithmetic

    • 7.6

    • 7.6.1 DAA Instruction

    • 7.6.2 DAS Instruction

    • 7.6.3 Section Review

  • Chapter Summary

  • Key Terms

Introduction to Integer Arithmetic in x86 Assembly

  • This chapter discusses the x86 assembly language shift and rotation instructions, focusing on bit manipulation in computer graphics, data encryption, and hardware manipulation.

  • Both high-level languages and x86 assembly allow arbitrary-length integer arithmetic; however, assembly provides more flexibility with specialized instructions for various operations. Operations on floating-point numbers will be covered in a later chapter.

7.1 Shift and Rotate Instructions

  • Shift instructions are critical in assembly language, utilized for moving bits right and left within an operand.

  • These instructions affect Overflow and Carry flags, forming a rich set of tools provided by x86 processors. The main commands include:

    • SHL (Shift Left)

    • SHR (Shift Right)

    • SAL (Shift Arithmetic Left)

    • SAR (Shift Arithmetic Right)

    • ROL (Rotate Left)

    • ROR (Rotate Right)

    • RCL (Rotate Carry Left)

    • RCR (Rotate Carry Right)

    • SHLD (Shift Left Double)

    • SHRD (Shift Right Double)

7.1.1 Logical Shifts and Arithmetic Shifts
  • Logical Shift: Fills created bit positions with 0. Example of logical right shift:

    • 11001111 → 01100111

    • The highest order bit becomes 0, and the least significant bit is copied to the Carry Flag.

  • Arithmetic Shift: Used for signed numbers. The created bit position gets filled with the original number's sign bit. Example:

    • 11001111 shifted right results in 11100111 (1 in the sign bit).

7.1.2 SHL Instruction
  • The SHL instruction performs a logical left shift on a destination operand, filling the lowest bit with 0. The highest bit moves to the Carry flag.

  • Format:
    SHL destination, count

  • It can operate on various operand types:

    • reg, imm8 (e.g., SHL reg, imm8)

    • mem, reg, CL (e.g., SHL mem, reg, CL)

    • imm8, mem, CL

Examples of SHL Instruction
  • Shifting binary to the left:

mov bl, 8Fh
shl bl, 1
; BL = 10001111b
; CF = 1, BL = 00011110b
7.1.3 SHR Instruction
  • The SHR instruction performs a logical right shift on the destination operand, replacing the highest bit with 0. It collects the lowest bit in the Carry flag.

  • SHR uses a similar format to SHL:
    SHR destination, count

Example of SHR Instruction
mov al, ODOh
shr al, 1
; AL = 01101000b, CF = 0
7.1.4 SAL and SAR Instructions
  • SAL works like SHL, shifting bits left and filling the lowest with 0, affecting the Carry flag similarly.

  • SAR duplicates the sign bit in arithmetic shifts to preserve the number’s sign.

7.1.5 ROL Instruction
  • ROL rotates bits left, with the highest bit going to both the Carry flag and the lowest position.

7.1.6 ROR Instruction
  • ROR rotates bits right, moving the lowest bit to the Carry and the highest position.

7.1.7 RCL and RCR Instructions
  • RCL shifts bits left, copying the Carry flag to the lowest bit and transferring the highest bit to the Carry flag.

  • RCR shifts bits right, with the Carry flag being copied to the highest bit.

7.1.8 Signed Overflow
  • Signed overflow occurs in integer operations that exceed the storage capacity of the operand. The Overflow flag is set when the sign of a number is reversed after shifting.

Example of Overflow Condition
mov al, +127
rol al, 1
; OF = 1, resulting AL = 01111111b
7.1.9 SHLD/SHRD Instructions
  • SHLD shifts a destination operand left, filling open positions from the source operand's most significant bits.

  • SHRD does the same but shifts right, filling from the least significant bits of the source operand.

  • Example of SHLD:

SHLD destination, source, count


Execute to move high bits into low positions in destination.

7.2 Shift and Rotate Applications

7.2.1 Shifting Multiple Doublewords
  • Multiple elements in an array can be shifted. The storage format is typically little-endian, where low-order bytes are placed first in memory.

7.2.2 Multiplication by Shifting Bits
  • Multiplication can be optimized using shifts to multiply unsigned numbers by powers of two, where shifting left (SHL) represents multiplying by $2^n$.

Example of Multiplication via SHL
  • To multiply by n:

mov eax, 5
shl eax, 1  ; EAX = 10
7.2.3 Displaying Binary Bits
  • BinToAsc procedure uses shifts to convert binary integer to ASCII binary, using the Carry flag for each bit.

7.2.4 Extracting File Date Fields
  • Applies bit manipulation to extract packed fields from a date stored in registers.

7.3 Multiplication and Division Instructions
  • Covers integer multiplcation instructions: MUL for unsigned and IMUL for signed multiplication.

7.3.1 Unsigned Integer Multiplication (MUL)
  • 8-bit or larger operations can be performed using MUL. Product is always twice the size of the operands. It sets flags based on upper half of product.

Example of MUL Instruction
mov al, 5h
mov bl, 10h
mul bl
; AX = 0050h
7.3.2 Signed Integer Multiplication (IMUL)
  • Similar to MUL, but also includes sign extension. Can be performed in one, two, or three operand formats.

7.3.3 Unsigned Integer Division (DIV)
  • DIV divides unsigned integers and is executed with respect to dividend and divisor sizes.

7.3.4 Signed Integer Division (IDIV)
  • IDIV divides signed integers and requires proper sign extension prior to execution.

7.3.5 Implementing Arithmetic Expressions
  • Implementation involves use of arithmetic operators and checking flags on overflow conditions.

7.4 Extended Addition and Subtraction
7.4.1 ADC Instruction
  • ADC adds both source operand and Carry flag into destination.

Example of ADC Instruction
mov al, FFh
add al, FFh
adc d1, 0
7.4.2 Extended Addition Example
  • Describes handling the carry through a loop in multiple byte addition.

7.4.3 SBB Instruction
  • SBB subtracts with carry, considered in extended precision operations.

7.5 ASCII and Unpacked Decimal Arithmetic

7.5.1 AAA Instruction
  • Adjusts ASCII digits after addition operations.

Example of AAA Instruction
mov ah, 0
mov al, '8'
add al, '2'
aaa
7.5.2 AAS Instruction
  • Adjusts ASCII results after subtraction, generally only if the result is below 0.

7.5.3 AAM Instruction
  • Converts results of multiplication into unpacked decimal for ASCII representation.

7.5.4 AAD Instruction
  • Converts unpacked decimal dividend to binary for division operations.

7.6 Packed Decimal Arithmetic

7.6.1 DAA Instruction
  • Converts the binary result of addition to packed decimal format.

Example of DAA Instruction
mov al, 35h
add al, 48h
daa
7.6.2 DAS Instruction
  • Adjusts results of subtraction to packed decimal format after SBB or SUB operations.

7.7 Chapter Summary

  • The chapter provided a comprehensive overview of integer arithmetic in assembly language, emphasizing shift instructions for multiplication and division.

  • Highlights include the details on signed versus unsigned instructions with practical implementation examples.


Chapter 7: Integer Arithmetic

Introduction to Integer Arithmetic in x86 Assembly

  • This chapter explores x86 assembly language shift and rotation instructions, which are fundamental for bit manipulation used in computer graphics, data encryption, and low-level hardware communication.

  • Assembly language provides ultimate flexibility compared to high-level languages by offering specialized instructions for multi-precision arithmetic and direct flag manipulation (e.g., Carry and Overflow flags).

7.1 Shift and Rotate Instructions

  • Shift instructions move bits left or right within a register or memory operand. The bit that is shifted "out" of the operand is typically moved into the Carry Flag (CF).

  • For all shift and rotate instructions, the count operand can either be an 8-bit immediate value (imm8) or the CLCL register.

7.1.1 Logical Shifts vs. Arithmetic Shifts

  • Logical Shift: Fills the newly created empty bit position with 00. It is typically used for unsigned numbers.

    • Example: 11001111 shifted right logically becomes 01100111.

  • Arithmetic Shift: Fills the newly created empty bit position with a copy of the original number's sign bit (the most significant bit). This preserves the sign of signed integers.

    • Example: 11001111 (signed negative) shifted right arithmetically becomes 11100111.

7.1.2 SHL Instruction

  • SHL (Shift Left): Performs a logical left shift. The highest bit is moved into the Carry flag, and the lowest bit is filled with 00.

  • Mathematical Application: Shifting left by nn bits is equivalent to multiplying the unsigned operand by 2n2^n.

  • Format: SHL destination, count (where destination is reg or mem).

7.1.3 SHR Instruction

  • SHR (Shift Right): Performs a logical right shift. The lowest bit is moved into the Carry flag, and the highest bit is filled with 00.

  • Mathematical Application: Shifting right by nn bits is equivalent to performing unsigned division by 2n2^n.

7.1.4 SAL and SAR Instructions

  • SAL (Shift Arithmetic Left): Identical to the SHL instruction.

  • SAR (Shift Arithmetic Right): Performs an arithmetic right shift. It duplicates the sign bit to the right, which effectively performs signed division by 2n2^n (rounding toward negative infinity).

7.1.5 ROL and ROR Instructions

  • ROL (Rotate Left): Shifts each bit to the left. The highest bit "wraps around" to the lowest bit position and is also copied to the Carry flag.

  • ROR (Rotate Right): Shifts each bit to the right. The lowest bit "wraps around" to the highest bit position and is also copied to the Carry flag.

7.1.7 RCL and RCR Instructions

  • RCL (Rotate Carry Left): Rotates the bits left through the Carry flag. The Carry flag is moved into the lowest bit, and the highest bit is moved into the Carry flag.

  • RCR (Rotate Carry Right): Rotates the bits right through the Carry flag. The Carry flag is moved into the highest bit, and the lowest bit is moved into the Carry flag.

7.1.8 Signed Overflow

  • In a single-position shift, the Overflow Flag (OF) is set if the sign bit changes. For example, if a positive number becomes negative after a shift, OF=1OF = 1.

7.1.9 SHLD/SHRD Instructions

  • SHLD (Shift Left Double): Shifts a destination operand to the left and fills the vacated bits with the most significant bits of a source operand.

  • SHRD (Shift Right Double): Shifts a destination operand to the right and fills the vacated bits with the least significant bits of a source operand.

7.2 Shift and Rotate Applications

  • Multi-Doubleword Shifting: To shift an array of bits, you shift the first element and then use RCL or RCR to propagate the Carry flag through the subsequent elements.

  • Fast Multiplication: Using combinations of SHL and ADD allows fast multiplication by constants. For instance, multiplying by 1010 is equivalent to (EAX×8)+(EAX×2)(EAX \times 8) + (EAX \times 2).

7.3 Multiplication and Division Instructions

7.3.1 Unsigned Integer Multiplication (MUL)

  • MUL takes one operand (the multiplier). The multiplicand is implied based on size:

    • 8-bit: AL×reg/mem8AXAL \times reg/mem8 \rightarrow AX

    • 16-bit: AX×reg/mem16DX:AXAX \times reg/mem16 \rightarrow DX:AX

    • 32-bit: EAX×reg/mem32EDX:EAXEAX \times reg/mem32 \rightarrow EDX:EAX

  • The Carry and Overflow flags are set if the upper half of the product is non-zero.

7.3.2 Signed Integer Multiplication (IMUL)

  • IMUL preserves the sign of the product by performing sign extension.

  • Unlike MUL, IMUL supports three formats: single operand (implied), two operands (destination, source), and three operands (destination, source, immediate).

7.3.3 Unsigned Integer Division (DIV)

  • DIV performs unsigned division. The dividend is twice the size of the divisor:

    • 8-bit divisor: Dividend in AXAX; Quotient in ALAL, Remainder in AHAH.

    • 16-bit divisor: Dividend in DX:AXDX:AX; Quotient in AXAX, Remainder in DXDX.

    • 32-bit divisor: Dividend in EDX:EAXEDX:EAX; Quotient in EAXEAX, Remainder in EDXEDX.

7.3.4 Signed Integer Division (IDIV)

  • Before using IDIV, the dividend must be sign-extended into the higher register using instructions like CBW (Convert Byte to Word), CWD (Convert Word to Doubleword), or CDQ (Convert Doubleword to Quadword).

7.4 Extended Addition and Subtraction

  • ADC (Add with Carry): Adds the source, destination, and the current value of the Carry flag. This is essential for adding integers larger than 3232 bits (e.g., adding two 6464-bit integers using two 3232-bit additions).

  • SBB (Subtract with Borrow): Subtracts the source and the Carry flag from the destination.

7.5 ASCII and BCD Arithmetic

  • ASCII/Unpacked BCD: Stores one digit per byte (e.g., 05h05h). Instructions like AAA (Adjust After Addition) and AAS (Adjust After Subtraction) correct the ALAL register after arithmetic on these formats.

  • Packed BCD: Stores two decimal digits per byte (e.g., 35h35h represents decimal 3535).

    • DAA (Decimal Adjust after Addition): Corrects the result of an ADD or ADC operation into packed BCD format.

    • DAS (Decimal Adjust after Subtraction): Corrects the result of a SUB or SBB operation into packed BCD format.


7.1 Shift and Rotate Instructions

Shift instructions are used to move the bit pattern within a register or memory location to the left or right. These operations are essential for low-level performance tuning, such as bitmasking and efficient arithmetic.

7.1.1 Logical vs. Arithmetic Shifts

  • Logical Shifts (SHL, SHR): These instructions treat the operand as a collection of bits without regard for a sign bit.

    • SHL (Shift Left) fills the vacated rightmost bit with 00. The bit shifted out of the MSB (Most Significant Bit) enters the Carry Flag (CFCF).

    • SHR (Shift Right) fills the vacated leftmost bit with 00. The bit shifted out of the LSB (Least Significant Bit) enters the CFCF.

  • Arithmetic Shifts (SAL, SAR): These instructions are designed for signed integers.

    • SAL (Shift Arithmetic Left) is functionally identical to SHL because shifting a signed number left by one bit always moves the sign bit.

    • SAR (Shift Arithmetic Right) performs a "sign-extend" operation. Instead of filling the MSB with 00, it fills it with a copy of the existing sign bit. This preserves the signedness (positive or negative) of the value.

7.1.2 Register and Operand Constraints

In x86 assembly, the count operand for shifts and rotates has specific restrictions:

  • It can be an 8-bit immediate value (imm8imm8).

  • It can be the CLCL register (lower 8 bits of ECXECX).

  • The processor masks the count to 5 bits (0–31), meaning shifting by 32 results in a shift of 0 on 32-bit registers.

7.1.3 Advanced Rotate Instructions

  • ROL and ROR: These instructions effectively create a circular buffer. Bits pushed out of one end are moved into the other end. These are frequently used in hashing algorithms and encryption (like DES or AES).

  • RCL and RCR (Rotate Through Carry): These instructions treat the Carry Flag as a 9th bit (for 8-bit operands) or a 33rd bit (for 32-bit operands). The CFCF is moved into the destination, and the bit shifted out becomes the new CFCF. This is critical for moving bits across byte or word boundaries.

7.1.4 SHLD and SHRD

These instructions shift bits between two operands:

  • SHLD dest, src, count: Shifts dest to the left. The vacated bits in dest are filled with the highest-order bits of src. src remains unchanged.

  • SHRD dest, src, count: Shifts dest to the right. The vacated bits in dest are filled with the lowest-order bits of src. src remains unchanged.

  • These are highly useful for bit-stream manipulation where data does not align with byte boundaries.

7.2 Shift Applications: Fast Arithmetic
  • Multiplication: SHL by nn is equivalent to multiplying by 2n2^n. To multiply by a non-power of two, such as 1010, assembly programmers use (EAX×23)+(EAX×21)(EAX \times 2^3) + (EAX \times 2^1).

  mov ebx, eax
  shl eax, 3   ; eax = val * 8
  shl ebx, 1   ; ebx = val * 2
  add eax, ebx ; eax = val * 10
  • Division: SHR (unsigned) or SAR (signed) by nn is equivalent to division by 2n2^n. Note that SAR rounds toward negative infinity, which differs slightly from the IDIV instruction (which rounds toward zero).

7.3 Multiplication and Division

7.3.1 Unsigned Multiplication (MUL)

MUL uses an implicit multiplicand based on the size of the multiplier:

  • 8-bit: AX=AL×srcAX = AL \times src

  • 16-bit: DX:AX=AX×srcDX:AX = AX \times src

  • 32-bit: EDX:EAX=EAX×srcEDX:EAX = EAX \times src

  • Flags: If the upper half of the result (e.g., AHAH, DXDX, or EDXEDX) is non-zero, the Carry (CFCF) and Overflow (OFOF) flags are set to 1. This signals that the result exceeded the original operand size.

7.3.2 Signed Multiplication (IMUL)

IMUL supports more flexible syntax than MUL:

  1. Single Operand: Same as MUL but performs signed multiplication.

  2. Two Operands: IMUL reg, reg/mem (The result is truncated to fit the destination register).

  3. Three Operands: IMUL reg, reg/mem, imm (Multiplies source by immediate and stores in destination).

7.3.3 Division (DIV/IDIV)

Division requires the dividend to be twice the size of the divisor.

  • Implicit Layouts:

    • 32-bit Divisor: Dividend is in EDX:EAXEDX:EAX. Quotient is stored in EAXEAX, Remainder in EDXEDX.

  • Divide Overflow: This occurs if the quotient is too large to fit in the destination register (e.g., dividing a very large number by 1). This triggers a processor exception.

  • IDIV Sign Extension: For signed division, you must extend the sign of the dividend into the upper register before calling IDIV.

    • CBW: Convert Byte to Word (ALAXAL \to AX)

    • CWD: Convert Word to Doubleword (AXDX:AXAX \to DX:AX)

    • CDQ: Convert Doubleword to Quadword (EAXEDX:EAXEAX \to EDX:EAX)

7.4 Extended Precision Arithmetic

7.4.1 ADC and SBB

  • ADC (Add with Carry): Computes dest = dest + src + CF.

  • SBB (Subtract with Borrow): Computes dest = dest - (src + CF).

  • These are used to perform arithmetic on integers wider than 32 bits. For example, to add two 64-bit integers:

  add eax, ebx   ; Add lower 32 bits
  adc edx, ecx   ; Add upper 32 bits plus carry
7.5 Decimal Arithmetic (BCD)

7.5.1 Unpacked BCD and ASCII

  • Standard ASCII digits ('0' to '9') are stored as 30h30h to 39h39h.

  • AAA (Adjust After Addition): If the lower 4 bits of AL > 9 or the Auxiliary Carry (AFAF) is set, it increments AHAH and clears the high nibble of ALAL.

  • AAS, AAM, AAD: Perform similar adjustments for subtraction, multiplication, and division.

7.5.2 Packed BCD

Packed BCD stores two digits per byte (e.g., 00110101b0011 0101b for decimal 3535).

  • DAA (Decimal Adjust after Addition): Corrects the binary result of an ADD back into packed BCD format.

  • DAS (Decimal Adjust after Subtraction): Corrects the result after a SUB.

  • These adjustments rely heavily on the Auxiliary Carry Flag (AFAF), which tracks carries from bit 3 to bit 4.