SimplifyC++ Article
#18 Mastering GAS: A Complete Guide to the GNU Assembler.
#18 Mastering GAS: A Complete Guide to the GNU Assembler.
Series for explaining and teaching GNU GAS Assembler using AT&T syntax – all codes are reviewed and tested daily on
Fedora Linux 42
GNU Assembler version 2.44-6
Arithmetic Operations (add, sub, mul, div)
Arithmetic operations are fundamental to virtually all programming tasks. These operations allow you to perform basic mathematical calculations like addition, subtraction, multiplication, and division, which are essential in low-level programming. In assembly language, arithmetic instructions typically operate directly on registers or memory locations. Understanding how to use these instructions in GAS (GNU Assembler) is crucial to manipulating numerical data in assembly.
GAS provides a variety of arithmetic instructions, including add, sub, mul, and div. These instructions are available across a wide range of architectures (e.g., x86, x86-64, ARM, MIPS, RISC-V), although there are some architecture-specific variations and optimizations.
add (Addition)
The add instruction is used to perform addition between two operands and store the result in a destination operand, typically a register. The operands can be registers or immediate values. This instruction is straightforward and is often used for tasks such as incrementing a value, adding offsets, or performing calculations.
Syntax:
add source,destinationdestination: The register or memory location where the result of the addition is stored.
source: The value to be added to the destination (could be an immediate, a register, or a memory address).
Example:
addl %eax, %ebx #Add the value in EBX to the value in EAX and store the result in EBX (x86)addl $5, %eax #Add the immediate value 5 to the value in EAX and store the result in EAX (x86-64)In this example:
The first instruction adds the value in
EBXtoEAXand stores the result inEBX.The second instruction adds the immediate value
5to the value inEAX.
Key Points:
The result is always stored in the destination operand.
The addition operation updates the flags (carry, zero, sign, etc.) in the processor status register, which can be used for conditional jumps or decision-making.
2.2 sub (Subtraction)
The sub instruction is used to subtract one operand from another. Similar to add, the subtraction is performed between two operands, and the result is stored in the destination operand. Subtraction is essential for tasks like calculating differences, adjusting values, or reducing counters.
Syntax:
sub source, destinationsource: The value to subtract from the destination (could be an immediate, a register, or a memory address).
destination: The register or memory location where the result of the subtraction is stored.
Example:
subl %ebx, %eax # Subtract the value in EBX from EAX and store the result in EAX (x86)subl $10, %eax # Subtract the immediate value 10 from EAX and store the result in EAX (x86-64)In this example:
The first instruction subtracts the value in
EBXfromEAXand stores the result inEAX.The second instruction subtracts the immediate value
10fromEAX.
Key Points:
Similar to
add, thesubinstruction affects the processor flags (borrow, zero, sign, etc.), which can be used to control program flow.Negative results and overflow conditions are handled by updating these flags.
mul (Multiplication)
The mul instruction is used for unsigned multiplication of two operands. It is generally used for multiplying registers or a register with an immediate value. Unlike addition and subtraction, multiplication can produce larger results that require more than one register to store.
Syntax (x86, x86-64):
mul operandoperand: This is the value to multiply the accumulator register (usually
eaxorrax) with. The result is placed in a pair of registers.
Example (x86):
mull %eax # Multiply the value in EAX by the value in the accumulator (AX)The result of the multiplication is stored in a special pair of registers:
EDX:EAXfor the x86 architecture. TheEAXregister holds the lower 32 bits of the result, whileEDXholds the upper 32 bits.On x86-64,
raxis the accumulator, and the result will be stored inrdx:rax.
Key Points:
The
mulinstruction multiplies the value in the accumulator register (usuallyEAX/RAX) by the operand, storing the result in the accumulator and the high register.This instruction does not affect the flags by default, but in some cases, you might need to handle overflow explicitly.
In GAS,
mulis for unsigned multiplication. For signed multiplication, the signed versionimulis used.
div (Division)
The div instruction performs an unsigned division. It divides the value in the accumulator register by the operand and stores the quotient and remainder in separate registers. As with multiplication, the result of division often involves multiple registers to handle large numbers.
Syntax (x86, x86-64):
div operandoperand: The divisor, the value by which the contents of the accumulator will be divided.
Example (x86):
divl %ebx # Divide the value in the accumulator (EDX:EAX) by the value in EBX (x86)The result of the division is stored as follows:
The quotient is placed in
EAX.The remainder is placed in
EDX.
Key Points:
Division by zero is a common exception that must be handled, as
divdoes not perform this check.The
divinstruction operates on theEDX:EAXpair for 32-bit numbers andRDX:RAXfor 64-bit numbers.The signed version of division (
idiv) is used when dealing with signed operands.
Arithmetic Operations Summary:
add: Adds two operands and stores the result in the destination operand.sub: Subtracts the source operand from the destination operand and stores the result in the destination operand.mul: Performs an unsigned multiplication between the accumulator register and the operand, storing the result in a pair of registers (e.g.,EDX:EAX).div: Divides the value in the accumulator register by the operand, storing the quotient and remainder in separate registers.
These arithmetic instructions form the backbone of many computational tasks in assembly programming. They are widely used for mathematical operations such as calculations, address arithmetic, and data processing. Each of these instructions may behave slightly differently across various architectures (e.g., x86, ARM, MIPS), but their core functionality remains similar, providing the ability to perform fundamental arithmetic operations directly on the processor's registers or memory.