4.3 Operating on Different Sized Operands
Occasionally you may need to compute some value 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 eight bit value to the sixteen bit value). Sometimes, you cannot specify the order of the operations. Perhaps the sixteen bit value is already in the AX register and you want to add an eight 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 eight bit signed operand to a sixteen 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 stackAnother 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 eight 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 );
|