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, countIt 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:
MULfor unsigned andIMULfor 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
countoperand can either be an 8-bit immediate value (imm8) or the register.
7.1.1 Logical Shifts vs. Arithmetic Shifts
Logical Shift: Fills the newly created empty bit position with . It is typically used for unsigned numbers.
Example:
11001111shifted right logically becomes01100111.
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 becomes11100111.
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 .
Mathematical Application: Shifting left by bits is equivalent to multiplying the unsigned operand by .
Format:
SHL destination, count(where destination isregormem).
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 .
Mathematical Application: Shifting right by bits is equivalent to performing unsigned division by .
7.1.4 SAL and SAR Instructions
SAL (Shift Arithmetic Left): Identical to the
SHLinstruction.SAR (Shift Arithmetic Right): Performs an arithmetic right shift. It duplicates the sign bit to the right, which effectively performs signed division by (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, .
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
RCLorRCRto propagate the Carry flag through the subsequent elements.Fast Multiplication: Using combinations of
SHLandADDallows fast multiplication by constants. For instance, multiplying by is equivalent to .
7.3 Multiplication and Division Instructions
7.3.1 Unsigned Integer Multiplication (MUL)
MULtakes one operand (the multiplier). The multiplicand is implied based on size:8-bit:
16-bit:
32-bit:
The Carry and Overflow flags are set if the upper half of the product is non-zero.
7.3.2 Signed Integer Multiplication (IMUL)
IMULpreserves the sign of the product by performing sign extension.Unlike
MUL,IMULsupports three formats: single operand (implied), two operands (destination, source), and three operands (destination, source, immediate).
7.3.3 Unsigned Integer Division (DIV)
DIVperforms unsigned division. The dividend is twice the size of the divisor:8-bit divisor: Dividend in ; Quotient in , Remainder in .
16-bit divisor: Dividend in ; Quotient in , Remainder in .
32-bit divisor: Dividend in ; Quotient in , Remainder in .
7.3.4 Signed Integer Division (IDIV)
Before using
IDIV, the dividend must be sign-extended into the higher register using instructions likeCBW(Convert Byte to Word),CWD(Convert Word to Doubleword), orCDQ(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 bits (e.g., adding two -bit integers using two -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., ). Instructions like
AAA(Adjust After Addition) andAAS(Adjust After Subtraction) correct the register after arithmetic on these formats.Packed BCD: Stores two decimal digits per byte (e.g., represents decimal ).
DAA (Decimal Adjust after Addition): Corrects the result of an
ADDorADCoperation into packed BCD format.DAS (Decimal Adjust after Subtraction): Corrects the result of a
SUBorSBBoperation 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 . The bit shifted out of the MSB (Most Significant Bit) enters the Carry Flag ().SHR(Shift Right) fills the vacated leftmost bit with . The bit shifted out of the LSB (Least Significant Bit) enters the .
Arithmetic Shifts (
SAL,SAR): These instructions are designed for signed integers.SAL(Shift Arithmetic Left) is functionally identical toSHLbecause 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 , 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 ().
It can be the register (lower 8 bits of ).
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
ROLandROR: 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).RCLandRCR(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 is moved into the destination, and the bit shifted out becomes the new . 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: Shiftsdestto the left. The vacated bits indestare filled with the highest-order bits ofsrc.srcremains unchanged.SHRD dest, src, count: Shiftsdestto the right. The vacated bits indestare filled with the lowest-order bits ofsrc.srcremains unchanged.These are highly useful for bit-stream manipulation where data does not align with byte boundaries.
7.2 Shift Applications: Fast Arithmetic
Multiplication:
SHLby is equivalent to multiplying by . To multiply by a non-power of two, such as , assembly programmers use .
mov ebx, eax
shl eax, 3 ; eax = val * 8
shl ebx, 1 ; ebx = val * 2
add eax, ebx ; eax = val * 10
Division:
SHR(unsigned) orSAR(signed) by is equivalent to division by . Note thatSARrounds toward negative infinity, which differs slightly from theIDIVinstruction (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:
16-bit:
32-bit:
Flags: If the upper half of the result (e.g., , , or ) is non-zero, the Carry () and Overflow () 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:
Single Operand: Same as
MULbut performs signed multiplication.Two Operands:
IMUL reg, reg/mem(The result is truncated to fit the destination register).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 . Quotient is stored in , Remainder in .
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 ()CWD: Convert Word to Doubleword ()CDQ: Convert Doubleword to Quadword ()
7.4 Extended Precision Arithmetic
7.4.1 ADC and SBB
ADC(Add with Carry): Computesdest = dest + src + CF.SBB(Subtract with Borrow): Computesdest = 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 to .
AAA(Adjust After Addition): If the lower 4 bits of AL > 9 or the Auxiliary Carry () is set, it increments and clears the high nibble of .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., for decimal ).
DAA(Decimal Adjust after Addition): Corrects the binary result of anADDback into packed BCD format.DAS(Decimal Adjust after Subtraction): Corrects the result after aSUB.These adjustments rely heavily on the Auxiliary Carry Flag (), which tracks carries from bit 3 to bit 4.