• Welcome to Jose's Read Only Forum 2023.
 

Mini tute, Intel complex addressing mode. in PBCC50

Started by Steve Hutchesson, December 21, 2009, 06:52:41 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Steve Hutchesson

Many people learning x86 assembler have problems with the notation but once you understand how it works, it is in fact very clear precise notation that you know exactly what it is doing.

Here is a small tute showing how it works in PowerBASIC.


#IF 0  ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    Build with PBCC50

    Intel complex addressing mode.

    BASE REGISTER --- INDEX --- MULTIPLIER --- DISPLACEMENT

    mov esi, address    ; ESI as base register
    mov edi, 16         ; EDI as the INDEX

    mov eax, [esi+edi*4+128]

    copy the contents at address + index times 4 + displacement into register EAX


#ENDIF ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FUNCTION PBmain as LONG

    #REGISTER NONE

    LOCAL svar as LONG
    LOCAL uvar as DWORD
    LOCAL parr as DWORD

    dim iarr(0 to 9) as LONG        ' dimension a 10 item integer array

    iarr(0) = 0000
    iarr(1) = 1111
    iarr(2) = 2222
    iarr(3) = 3333
    iarr(4) = 4444
    iarr(5) = 5555
    iarr(6) = 6666
    iarr(7) = 7777
    iarr(8) = 8888
    iarr(9) = 9999

    parr = VarPtr(iarr(0))          ' get the address of the first element

    ! mov esi, parr                 ' use ESI as the BASE  REGISTER
    ! xor edi, edi                  ' use EDI as the INDEX REGISTER

  ' --------------------------------
  ' read array by altering the INDEX
  ' --------------------------------
    ! mov eax, [esi+edi*4]          ' get the content of member ZERO in one instruction
    ! mov uvar, eax
    cout ustr(uvar)

    ! add edi, 6
    ! mov eax, [esi+edi*4]          ' get the content of member SIX in one instruction
    ! mov uvar, eax
    cout ustr(uvar)

  ' ---------------------------------------
  ' read array by altering the displacement
  ' ---------------------------------------
    ! mov eax, [esi+16]             ' get the contents of member 4 in one instruction
    ! mov uvar, eax
    cout ustr(uvar)

    ! mov eax, [esi+32]             ' get the contents of member 8 in one instruction
    ! mov uvar, eax
    cout ustr(uvar)

  ' -----------------------------------------
  ' read from a BYTE table in one instruction
  ' zero extend it to 32 bit and display it
  ' -----------------------------------------

  ' Using this notation the location "ctable" is effectively a DISPLACEMENT.
  ' For it to work it is an OFFSET determined at compile time.

    ! movzx eax, BYTE PTR ctable[51]    ' disassembly >>>  movzx   eax,byte ptr [401453h]
    ! mov uvar, eax
    cout ustr(uvar)

  ' setting a register like an INDEX changes the output OPCODE
  ' EDI becomes the BASE REGISTER and the location "ctable"
  ' is a DISPLACEMENT added to it.

    ! mov edi, 66                       ' set the INDEX
    ! movzx eax, BYTE PTR ctable[edi]   ' disassembly >>>  movzx   eax,byte ptr [edi+401420h]
    ! mov uvar, eax
    cout ustr(uvar)

    pause

    FUNCTION = 0
    Exit FUNCTION

  #align 4
  ctable:
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0        ' numbers
    ! db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1        ' upper case
    ! db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
    ! db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1        ' lower case
    ! db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    ! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    DECLARE FUNCTION cc_out CDECL LIB "MSVCRT.DLL" ALIAS "puts" (BYVAL ptxt AS DWORD) AS DWORD

SUB cout(a$)

  ' ***** Supported escapes *****
  ' \0 = ascii zero             0
  ' \t = tab                    9
  ' \n = newline               10
  ' \r = carriage return       13
  ' \q = double quote          34
  ' \\ = backslash             92
  ' *****************************

    #REGISTER NONE

    LOCAL src as DWORD
    LOCAL dst as DWORD
    LOCAL sln as DWORD

    src = StrPtr(a$)

    ! mov esi, src
    ! mov edi, src

  stlp:
    ! mov al, [esi]
    ! add esi, 1

    ! cmp al, "\"
    ! jne nxt

' ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤

    ! cmp BYTE PTR [esi], "n"
    ! jne lb1
    ! add esi, 1
    ! mov BYTE PTR [edi], 10
    ! add edi, 1
    ! jmp stlp
  lb1:

    ! cmp BYTE PTR [esi], "r"
    ! jne lb2
    ! add esi, 1
    ! mov BYTE PTR [edi], 13
    ! add edi, 1
    ! jmp stlp
  lb2:

    ! cmp BYTE PTR [esi], "t"
    ! jne lb3
    ! add esi, 1
    ! mov BYTE PTR [edi], 9
    ! add edi, 1
    ! jmp stlp
  lb3:

    ! cmp BYTE PTR [esi], "0"
    ! jne lb4
    ! add esi, 1
    ! mov BYTE PTR [edi], 0
    ! add edi, 1
    ! jmp stlp
  lb4:

    ! cmp BYTE PTR [esi], "\"
    ! jne lb5
    ! add esi, 1
    ! mov BYTE PTR [edi], 92
    ! add edi, 1
    ! jmp stlp
  lb5:

    ! cmp BYTE PTR [esi], "q"
    ! jne lb6
    ! add esi, 1
    ! mov BYTE PTR [edi], 34
    ! add edi, 1
    ! jmp stlp
  lb6:

' ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤

  nxt:
    ! mov [edi], al
    ! add edi, 1
    ! test al, al
    ! jnz stlp

    ! sub edi, src
    ! mov sln, edi

    cesc$ = left$(a$,sln)

    cc_out StrPtr(cesc$)

END SUB

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    MACRO INPUT_HANDLE  = -10&
    DECLARE FUNCTION kbflush LIB "KERNEL32.DLL" ALIAS "FlushConsoleInputBuffer" ( _
                     BYVAL hConsoleInput AS DWORD) AS LONG
    DECLARE FUNCTION hStdIn LIB "KERNEL32.DLL" ALIAS "GetStdHandle" ( _
                     BYVAL nStdHandle AS DWORD) AS DWORD
    DECLARE FUNCTION SysYield LIB "KERNEL32.DLL" ALIAS "Sleep" ( _
                     BYVAL msWait AS DWORD) AS LONG
    DECLARE FUNCTION keypress CDECL LIB "MSVCRT.DLL" ALIAS "_kbhit" () as DWORD
    DECLARE FUNCTION putz CDECL LIB "MSVCRT.DLL" ALIAS "puts" (BYVAL ptxt AS DWORD) AS DWORD

' -------------------------------------------

SUB pause()

    txt$ = "Press any key to continue ...."
    putz StrPtr(txt$)
    kbflush hStdIn(INPUT_HANDLE)

  lbl0:
    SysYield 20
    keypress
    ! test eax, eax
    ! jz lbl0

END SUB

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    DECLARE FUNCTION ltoa CDECL LIB "MSVCRT.DLL" ALIAS "_ltoa" ( _
                     ByVal lval as LONG,ByVal pstr as DWORD,ByVal radix as DWORD) as DWORD

' -------------------------------------------

FUNCTION sstr(ByVal lval as LONG) as STRING

    LOCAL astring as ASCIIZ * 32

    ltoa(lval,VarPtr(astring),10)

    FUNCTION = astring

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    DECLARE FUNCTION c_ultoa CDECL LIB "MSVCRT.DLL" ALIAS "_ultoa" ( _
                     ByVal uint as DWORD,ByVal pstr as DWORD,ByVal radix as DWORD) as DWORD

' -------------------------------------------

FUNCTION ustr(ByVal uint as DWORD) as STRING

    LOCAL astring as ASCIIZ * 32

    c_ultoa(uint,VarPtr(astring),10)

    FUNCTION = astring

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    DECLARE FUNCTION c_atoi CDECL LIB "MSVCRT.DLL" ALIAS "atoi" (ByVal ptxt as DWORD) as DWORD

FUNCTION atoi(number$) as DWORD

    FUNCTION = c_atoi(StrPtr(number$))

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    DECLARE FUNCTION c_atol CDECL LIB "MSVCRT.DLL" ALIAS "atol" (ByVal ptxt as DWORD) as LONG

FUNCTION atol(number$) as LONG

    FUNCTION = c_atol(StrPtr(number$))

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

Mike Lobanovsky

#1
Thank you Steve,

I think your code can be very helpful to many for starters.

Mike Lobanovsky
Mike
(3.6GHz Intel Core i5 w/ 16GB RAM, 2 x GTX 650Ti w/ 2GB VRAM, Windows 7 Ultimate Sp1)