Indirect Addressing

Indirect addressing uses an operand that contains an address. This is achieved by the following two statements in program ASM_Indirect

LEA EAX, Int1; //   Load the address of Int1 into the accumulator.
MOV [EAX], EDX; // Copy the contents of EDX to Int1.  

Program ASM_Indirect is a simple illustration of how one line of code containing an indirect operand can be used to store data to different addresses. The program loads a second address into the accumulator (the address Int2) and uses the same line of code to copy the contents of EDX.

(Indirect addressing adds versatility in an analogous way to using a variable instead of a literal value in high-level code. The address itself becomes a variable).

 program ASM_Indirect;
  {$APPTYPE CONSOLE}
  {$ASMMODE INTEL} //Delete this line in Delphi
uses
  SysUtils;
var
  Int1, Int2 : integer;
begin
  asm
    MOV EDX, 10
    // Load the address Int1 into the accumulator.
    LEA EAX, Int1 
    MOV [EAX], EDX //Copy the contents of EDX to Int1.
     // Load the address Int2 into the accumulator.
    LEA EAX, Int2
    MOV [EAX], EDX //Copy the contents of EDX to Int2.
  end;
  writeln('Int1: ', Int1);
  writeln('Int2: ', Int2);
  readln;
end.

program ASM_IndirectA;
  {$mode objfpc}{$H+}
  {$ASMMODE ATT}
uses
  SysUtils;
var
  Int1, Int2 : integer;
begin
  asm
    MOV $0xA, %EDX
    // Load the address Int1 into the accumulator.
    LEA Int1, %EAX
    MOV %EDX, (%EAX) //Copy the contents of EDX to Int1.
    // Load the address Int2 into the accumulator.
    LEA Int2, %EAX
    MOV %EDX,(%EAX) //Copy the contents of EDX to Int2.
  end;
  writeln('Int1: ', Int1);
  writeln('Int2: ', Int2);
  readln;
end.
 

Program ASM_Array2d is a useful but more complicated example. The base register is modified within a loop to change the row index of the array. The program uses indexed, indirect addressing. Try to predict the output.

program ASM_Array2d;
  {$APPTYPE CONSOLE}
  {$ASMMODE INTEL}
uses
  SysUtils;
const
  MAX_ROW = 8;
  MAX_COL = 5;
var
  Table : array[1..MAX_ROW,1..MAX_COL] of byte;
  Row, Col : integer;
begin
  asm
    MOV DL, 0 //DL to contain current byte
    MOV DH, 0 //zero based row count
    LEA EAX, Table //Accumulator will be base register
    @StartRow:
      ADD DL, 10 //Left digit is row number.
      MOV ECX, 0  //zero based col count
        @StartCol:
          INC DL //Right digit is column number.
          //Use indirect indexed addressing to put cell value in table
          MOV  [ECX + EAX], DL  
          INC ECX
          CMP ECX, MAX_COL
        JNE @StartCol
      INC DH
      SUB DL, MAX_COL // Right digit becomes 0
      ADD EAX, MAX_COL  //Change the address in the base register
      CMP DH, MAX_ROW
    JNE @StartRow
  end;
  for row := 1 to MAX_ROW do
    begin
      for col := 1 to MAX_COL do
        begin
          write(Table[Row,Col], ' ');
        end;
      writeln;
    end;
  readln;
end.

program ASM_Array2D_A;
  {$mode objfpc}{$H+}
  {$ASMMODE ATT}
uses
  SysUtils;
const
  MAX_ROW = 8;
  MAX_COL = 5;
var
  Table : array[1..MAX_ROW,1..MAX_COL] of byte;
  Row, Col : integer;
begin
  asm
    MOV $0,%DL  //DL to contain current byte
    MOV $0,%DH //zero based row count
    LEA Table, %EAX //Accumulator will be base register
    .LStartRow:
      ADD $0xA, %DL //Left digit is row number.
      MOV $0, %ECX //zero based col count
        .LStartCol:
          INC %DL //Right digit is column number.
          //Use indirect indexed addressing to put cell value in table
          MOV  %DL, (%ECX,%EAX)
          INC %ECX
          CMP MAX_COL, %ECX
        JNE .LStartCol
      INC %DH
      SUB MAX_COL, %DL // Right digit becomes 0
      ADD MAX_COL, %EAX  //Change the address in the base register
      CMP MAX_ROW, %DH
    JNE .LStartRow
  end;
  for row := 1 to MAX_ROW do
    begin
      for col := 1 to MAX_COL do
        begin
          write(Table[Row,Col], ' ');
        end;
      writeln;
    end;
  readln;
end.
Programming - a skill for life!

Registers, addressing modes and flags