Quote: "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... " ... FBSL:
- Code: Select all
' =========================================================
' @2009 Steve Hutchesson http://www.masm32.com/board/index.php
' =========================================================
' ML: A few comments changed/added by me to impose Fbsl v3 syntax
' =========================================================
' 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
' ======================= S T A R T ==========================
#AppType Console
#Option Strict
Dim iarr[0 To 9] As Integer ' 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
DoIt(@iarr[0], AddressOf PrintIt) ' get the address of the first element ' ML: ... and the pointer to the printing routine
Pause
' ========================= E N D ===========================
' =========================================================
' ML: Wrapper to be called from Asm.
' Fbsl's Print does much conversion internally based on Fbsl's intrinsic
' data type evaluation which assembler has no knowing of. So use ByVal
' to suppress it and declare the incoming value as an explicit integer.
Sub PrintIt(ByVal What As Integer)
Print What
End Sub
' =========================================================
' =========================================================
' ML: "Push" instructions supply integer parameters for
' our PrintInt wrapper sub by passing them on stack.
' Both PrintIt and Print preserve ESI and EDI internally
' exactly like we do it in our Asm below so that they
' don't interphere with each other.
Asm DoIt(ArrayPointer As Integer, PrintItPointer As Integer)
' ML: That's exactly where they will be located on stack
#Define ArrayPointer [ebp + 8]
#Define PrintItPointer [ebp + 12]
.data ' ML: Static data storage is here
@ctable
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 0, 0: db 0, 0, 0: db 0 ' numbers
db 0, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1 ' upper case
db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 1, 0: db 0, 0, 0: db 0
db 0, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1 ' lower case
db 1, 1, 1: db 1, 1, 1: db 1, 1, 1: db 1, 1, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0, 0, 0: db 0
.code ' ML: Entry point is here
enter 0, 0 ' ML: Set up new stack frame
push esi ' ML: Preserve regs by convention
push edi
mov esi, ArrayPointer ' use ESI as the BASE REGISTER
xor edi, edi ' use EDI as the INDEX REGISTER ' ML: ... so clear it for now
' --------------------------------
' read array by altering the INDEX
' --------------------------------
push [esi + edi * 4] ' push the content of member ZERO in one instruction
call PrintItPointer
add edi, 6
push [esi + edi * 4] ' get the content of member SIX in one instruction
call PrintItPointer
' ---------------------------------------
' read array by altering the displacement
' ---------------------------------------
push [esi + 16] ' get the contents of member FOUR in one instruction
call PrintItPointer
push [esi + 32] ' get the contents of member EIGHT in one instruction
call PrintItPointer
' -----------------------------------------
' 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] ' ML: I have "movzx eax, [$00f5c52b]" in Delphi's disassembler
push eax
call PrintItPointer
' 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] ' ML: Confirmed: "movzx eax, [edi+$00f5c4f8]" for Fbsl
push eax
call PrintItPointer
pop edi ' ML: Restore regs saved by convention
pop esi
leave ' ML: Restore old stack frame
ret ' ML: Return control to Fbsl
End Asm
' =========================================================
Enjoy!

