PROWAREtech

articles » current » assembly » x86 » tutorial » page-11

Intel IA-32 Assembly Tutorial - A Guide to the Basics of x86 Assembly - Page 11

Language Elements (More on Integer Arithmetic: Logical Shifts vs Arithmetic Shifts, More on Instructions: Shift, Rotate, Multiply and Divide).

Integer Arithmetic

This section covers bit shift and bit rotate operations. Because multiplication is a left bit shift operation and division is a right bit shift operation, multiplication and division are covered in this section.

All of the instructions in the table below affect the Overflow and Carry Flags.

 Shift and Rotate Instructions Mnemonic Description 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 double-precision shift left SHRD double-precision shift right

Logical Shifts vs Arithmetic Shifts

A logical shift fills the newly created bit position with zero.

``````	mov al,10001111b
shl al,1         ;AL = 00011110b; CF = 1
mov al,10001111b
shr al,1         ;AL = 01000111b; CF = 1
mov al,11010000b
shr al,1         ;AL = 01101000b; CF = 0
``````

Fast, bit-wise multiplication using `SHL` is possible when you are multiplying by a base of 2. Shifting an unsigned integer n bits to the left multiplies it by 2n. For example, 8 is 23. Shift 3 to the left is multiply any number by 8.

``````	mov al,2         ;AL = 00000010b = 2 (02h)
shl al,3         ;AL = 00010000b = 16 (10h)
``````

Fast, bit-wise division using `SHR` is possible when you are dividing by a base of 2 operand. For example, 16 is 24. Shift 4 to the right is dividing any number by 16.

``````	mov al,32        ;AL = 00100000b = 32 (20h)
shr al,4         ;AL = 00000010b = 2 (02h)
``````

`SAL` (shift arithmetic left) is identical to `SHL`.

`SAR` can be used for signed division. `SAR` duplicates the sign bit.

``````	mov al,-128      ;AL = 10000000b = -128 (80h)
sar al,3         ;AL = 11110000b = -16 (F0h)
``````

The `ROL` instruction shifts each bit to the left and the highest bit is copied both into the Carry Flag and into the lowest bit. Bit rotation does not lose any bits like bit shifting does.

``````	mov al,40h       ;AL = 01000000b
rol al,1         ;AL = 10000000b; CF = 0
rol al,1		 ;AL = 00000001b; CF = 1
rol al,1		 ;AL = 00000010b; CF = 0
``````

Use `ROL` to exchange the upper bits with the lower bits.

``````	mov al,F1h
rol al,4         ;AL = 1Fh
``````

The `ROR` (rotate right) instruction shifts each bit to the right and copies the lowest bit into the Carry Flag and into the highest bit.

``````	mov al,1         ;AL = 00000001b
ror al,1         ;AL = 10000000b; CF = 1
ror al,1         ;AL = 01000000b; CF = 0
``````

The `RCL` (rotate carry left) instruction shifts each bit to the left, copies the Carry Flag into the least significant bit and copies the most significant bit into the Carry Flag.

``````	clc              ;CF = 0
mov bl,88h       ;CF = 0; BL = 10001000b (0 1000 1000)
rcl bl,1         ;CF = 1; BL = 00010000b (1 0001 0000)
rcl bl,1         ;CF = 0; BL = 00100000b (0 0010 0001)
``````

Recover a Bit from the Carry Flag: RCL can recover a bit that has previously been shifted into the Carry Flag.

``````	.data
byteval BYTE 01101010b
.code
shr byteval,1    ;shift least significant bit into Carry Flag
jc  quit_label   ;jump away if Carry Flag set
rcl byteval,1    ;otherwise, restore the number
``````

The `RCR` (rotate carry right) instruction shifts each bit to the right while copying the Carry Flag into the most significant bit and then copies the least significant bit into the Carry Flag.

``````	stc              ;CF = 1
mov ah,10h       ;CF = 1; AH = 00010000 (0001 0000 1)
rcr ah,1         ;CF = 0; AH = 10001000 (1000 1000 0)
``````

Shifting multiple doublewords:

``````	.data
ArraySize = 3
array DWORD ArraySize DUP (99999999h) ;9 = 1001b
.code
mov esi,0
shr array[esi+8],1                    ;high dword
rcr array[esi+4],1                    ;middle dword, include carry
rcr array[esi],1                      ;low dword, include carry
``````

The `MUL` (unsigned multiply) and `IMUL` (signed multiply) instructions multiply `EAX` by an operand. The product is stored in `EDX` and `EAX`. If, after the operation, EDX is not zero then the Carry Flag is set.

``````	mov eax,12345h
mov ebx,10000h
mul ebx          ;CF = 1, EDX:EAX = 00 00 00 01:23 45 00 00h
``````

The `DIV` instruction performs division on unsigned integers. A single operand is required and it must be either a register or memory operand. This operand is the divisor. The dividend is the `EDX:ECX` registers and the quotient is in the `EAX` register. The remainder is stored in `EDX`.

``````	.data
dividend QWORD 0000000800300020h
divisor	DWORD 00000100h
.code
mov edx,dword ptr dividend + 4 ;high dword
mov eax,dword ptr dividend     ;low dword
div divisor                    ;EAX = 08003000h, EDX = 00000020h
``````

Concerning signed integer division... These three instructions are needed. The `CBW` (convert byte to word) instruction extends the sign bit of `AL` into the `AH` register while preserving the number's sign. The `CWD` (convert word to doubleword) instruction extends the sign bit of the `AX` register into the `DX` register. The `CDQ` (convert doubleword to quadword) instruction extends the sign bit of the `EAX` register into the `EDX` register.

``````	.data
byteval SBYTE -65  ;9Bh
wordval SWORD -65  ;FF9Bh
dwrdval SDWORD -65 ;FFFFFF9Bh
.code
mov al,byteval
cbw                ;AX = FF9Bh
mov ax,wordval
cwd                ;DX:AX = FFFF:FF9Bh
mov eax,dwrdval
cdq                ;EDX:EAX = FFFFFFFF:FFFFFF9Bh
``````

The `IDIV` (signed divide) instruction performs signed integer division using the same operands as the `DIV` instruction, which requires that `EAX` be sign-extended into `EDX` using `CDQ` (convert doubleword into quadword).

``````	.data
dwrdval SDWORD -50000
.code
mov eax,dwrdval ;dividend low
cdq             ;extend EAX into EDX
mov ebx,256     ;divisor
idiv ebx        ;quotent EAX = -195; remainder EDX = -80
``````

If a divide operation has a quotient that is too large to fit into the destination operand then a divide overflow condition occurs. This and division by zero cause a CPU interrupt and the program halts.

The `SHRD` (shift right double-precision) and `SHLD` (shift left double-precision) shifts bits and then replaces them with the second operand based on the number of bits to shift specified in the third operand.

First, it should be made clear that these instructions are not use a lot and they are slow because they take a large number of cpu cycles to execute.

An example of using `SHRD` to pack data and `SHLD` to unpack data:

``````
xor esi, esi
mov eax, 100000CCh ; 0001 0000 0000 0000 0000 0000 1100 1100b
mov ebx, 1000004Fh ; 0001 0000 0000 0000 0000 0000 0100 1111b
mov ecx, 10000055h ; 0001 0000 0000 0000 0000 0000 0101 0101b
mov edx, 100000FFh ; 0001 0000 0000 0000 0000 0000 1111 1111b

; pack the data
shrd esi, eax, 3 ; esi = 80000000h = 1000 0000 0000 0000 0000 0000 0000 0000b
shr eax, 3
shrd esi, eax, 3 ; esi = 30000000h = 0011 0000 0000 0000 0000 0000 0000 0000b
shr eax, 3
shrd esi, eax, 2 ; esi = CC000000h = 1100 1100 0000 0000 0000 0000 0000 0000b
shr eax, 2

shrd esi, ebx, 3 ; esi = F9800000h = 1111 1001 1000 0000 0000 0000 0000 0000b
shr ebx, 3
shrd esi, ebx, 3 ; esi = 3F300000h = 0011 1111 0011 0000 0000 0000 0000 0000b
shr ebx, 3
shrd esi, ebx, 2 ; esi = 4FCC0000h = 0100 1111 1100 1100 0000 0000 0000 0000b
shr ebx, 2

shrd esi, ecx, 4 ; esi = 54FCC000h = 0101 0100 1111 1100 1100 0000 0000 0000b
shr ecx, 4
shrd esi, ecx, 4 ; esi = 554FCC00h = 0101 0101 0100 1111 1100 1100 0000 0000b
shr ecx, 4

shrd esi, edx, 1 ; esi = AAA7E600h = 1010 1010 1010 0111 1110 0110 0000 0000b
shr edx, 1
shrd esi, edx, 1 ; esi = D553F300h = 1101 0101 0101 0011 1111 0011 0000 0000b
shr edx, 1
shrd esi, edx, 1 ; esi = EAA9F980h = 1110 1010 1010 1001 1111 1001 1000 0000b
shr edx, 1
shrd esi, edx, 1 ; esi = F554FCC0h = 1111 0101 0101 0100 1111 1100 1100 0000b
shr edx, 1
shrd esi, edx, 4 ; esi = FF554FCCh = 1111 1111 0101 0101 0100 1111 1100 1100b
shr edx, 4

; do something with the packed data

; unpack the data this time using 8-bits this time
shld edx, esi, 8
shl esi, 8
shld ecx, esi, 8
shl esi, 8
shld ebx, esi, 8
shl esi, 8
shld eax, esi, 8
shl esi, 8

; eax = 100000CCh = 0001 0000 0000 0000 0000 0000 1100 1100b
; ebx = 1000004Fh = 0001 0000 0000 0000 0000 0000 0100 1111b
; ecx = 10000055h = 0001 0000 0000 0000 0000 0000 0101 0101b
; edx = 100000FFh = 0001 0000 0000 0000 0000 0000 1111 1111b
``````
[Page 11 of 15]