9.3 Operating on Different-Sized Operands


9.3 Operating on Different-Sized Operands

Occasionally you may need to do some computation on a pair of operands that are not the same size. For example, you may need to add a word and a double word together or subtract a byte value from a word value. The solution is simple: just extend the smaller operand to the size of the larger operand and then do the operation on two similarly sized operands. For signed operands, you would sign extend the smaller operand to the same size as the larger operand; for unsigned values, you zero extend the smaller operand. This works for any operation, although the following examples demonstrate this for the addition operation.

To extend the smaller operand to the size of the larger operand, use a sign extension or zero extension operation (depending upon whether you're adding signed or unsigned values). Once you've extended the smaller value to the size of the larger, the addition can proceed. Consider the following code that adds a byte value to a word value:

 static      var1: byte;      var2: word;            .            .            . // Unsigned addition:       movzx( var1, ax );       add( var2, ax ); // Signed addition: movsx( var1, ax ); add( var2, ax ); 

In both cases, the byte variable was loaded into the AL register, extended to 16 bits, and then added to the word operand. This code works out really well if you can choose the order of the operations (e.g., adding the 8-bit value to the 16- bit value). Sometimes, you cannot specify the order of the operations. Perhaps the 16-bit value is already in the AX register and you want to add an 8-bit value to it. For unsigned addition, you could use the following code:

       mov( var2, ax ); // Load 16-bit value into AX        .               // Do some other operations leaving        .               // a 16-bit quantity in AX.       add( var1, al ); // Add in the eight-bit value       adc( 0, ah );    // Add carry into the H.O. word. 

The first add instruction in this example adds the byte at var1 to the L.O. byte of the value in the accumulator. The adc instruction above adds the carry out of the L.O. byte into the H.O. byte of the accumulator. Care must be taken to ensure that this adc instruction is present. If you leave it out, you may not get the correct result.

Adding an 8-bit signed operand to a 16-bit signed value is a little more difficult. Unfortunately, you cannot add an immediate value (as above) to the H.O. word of AX. This is because the H.O. extension byte can be either $00 or $FF. If a register is available, the best thing to do is the following:

 mov( ax, bx ); // BX is the available register. movsx( var1, ax ); add( bx, ax ); 

If an extra register is not available, you might try the following code:

       push( ax );        // Save word value.       movsx( var1, ax ); // Sign extend 8-bit operand to 16 bits.       add( [esp], ax );  // Add in previous word value       add( 2, esp );     // Pop junk from stack 

Another alternative is to store the 16-bit value in the accumulator into a memory location and then proceed as before:

 mov( ax, temp ); movsx( var1, ax ); add( temp, ax ); 

All the examples above added a byte value to a word value. By zero or sign extending the smaller operand to the size of the larger operand, you can easily add any two different-sized variables together.

As a last example, consider adding an 8-bit signed value to a quadword (64-bit) value:

 static      QVal:qword;      BVal:int8;       .       .       .      movsx( BVal, eax );      cdq();      add( (type dword QVal), eax );      adc( (type dword QVal[4]), edx ); 




The Art of Assembly Language
The Art of Assembly Language
ISBN: 1593272073
EAN: 2147483647
Year: 2005
Pages: 246
Authors: Randall Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net