Page 1 of 1

Assembler : Working With Arrays A look at how arrays are handled in assembler

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 06 April 2010 - 08:55 AM

Assembler : Working With Arrays

Introduction

This tutorial looks at how we deal with arrays in assembler. we are going to extend our console application by reading in some user text from the console, and print it back in reverse.

New Instructions

We are introducing four new instruction to our repetoire in this tutorial

  • lea - load the effective address of a memory location into a register
  • dec - decrement a register or a memory location
  • or - perform a logical or on a register with memory, memory with a register, or a register with a register
  • jne - jump if not equal


The code

                    ; This is a console application that reads some text from the standard input
                    ; device and prints the string back to the output device, but in reverse

                    global      _mainCRTStartup         ; This is the main program entry point
                    extern      _ExitProcess@4          ; Windows API call to exit the process
                    extern      _GetStdHandle@4         ; Windows API call to get the standard output handle
                    extern      _ReadFile@20            ; Windows API call to read from a handle
                    extern      _WriteFile@20           ; Windows API call to write to a handle
                    
                    section     .data                   ; Start of the data segment

prompt              db          'Please enter some text', 10, 10
terminator          db          0                       ; The terminating character
input_string        times       256 db 0                ; Space for input message << This is our char array
bytes_read          dd          0                       ; Return 32-bit word from ReadFile
bytes_written       dd          0                       ; Return 32-bit word from WriteFile
input_handle        dd          0                       ; The standard input handle
output_handle       dd          0                       ; The standard output handle
new_lines           db          10, 10                  ; The new line characters

                    section        .code                ; Start of the code segment
                    
                    ; We need to get hold of the standard input and output handle so we can write
                    ; our text to it. This is provided by the GetStdHandle windows API call
                    
_mainCRTStartup:    push        -10                     ; We want the standard input handle
                    call        _GetStdHandle@4         ; Call the Windows API GetStdHandle to retrieve it
                    mov         [input_handle], eax     ; Save the handle for later use

                    push        -11                     ; We want the standard output handle
                    call        _GetStdHandle@4         ; Call the Windows API GetStdHandle to retrieve it
                    mov         [output_handle], eax    ; Save the handle for later use
                    
                    ; Output our request for some user text to the standard output stream
                    
                    push        0                       ; We do not want overlapped I/O
                    push        dword bytes_written     ; The address of the number of bytes written
                    push        24                      ; The length of the text we are writing
                    push        prompt                  ; The address of the text we are writing
                    push        dword [output_handle]   ; The handle returned from GetStdHandle call
                    call        _WriteFile@20           ; Write the text to the standard output handle
                    
                    ; Read in the text from the user into our input_string area
                    
                    push        0                       ; We do not want overlapped I/O
                    push        bytes_read              ; The address of the number of bytes read
                    push        256                     ; The length of the text we are reading
                    push        input_string            ; The address of the buffer for reading
                    push        dword [input_handle]    ; The handle returned from GetStdHandle call
                    call        _ReadFile@20            ; Read the text to the standard input handle
                    mov         edi, [bytes_read]       ; Load the number of bytes read into input_string
           
                    ; The start of our loop, and the position we return to if we want to
                    ; print out the next character
                   
start_loop:         
                    push        0                       ; We do not want overlapped I/O
                    push        dword bytes_written     ; The address of the number of bytes written
                    push        1                       ; The length of the text we are writing
                    lea         eax, [esi+edi]          ; Load the address of the byte to output
                    push        eax                     ; Stack the address of the char we are writing
                    push        dword [output_handle]   ; The handle returned from GetStdHandle call
                    call        _WriteFile@20           ; Write the text to the standard output handle
                    dec         edi                     ; Decrement the index field
                    mov         al, [esi+edi]           ; Load this previous byte 
                    or          al, al                  ; Set the condition code flags
                    jne         start_loop              ; Jump back to the start of the loop if not end
                    
                    push        0                       ; We do not want overlapped I/O
                    push        bytes_written           ; The address of the number of bytes written
                    push        2                       ; The length of the text we are writing
                    push        new_lines               ; The address of the text we are writing
                    push        dword [output_handle]   ; The handle returned from GetStdHandle call
                    call        _WriteFile@20           ; Write the text to the standard output handle

                    ; The text has been written, so all we need to do now is exit the
                    ; process and return control back to the console
                    
                    push        0                       ; Stack the exit code
                    call        _ExitProcess@4          ; Exit the process



We should be familiar now with the code upto the start_loop, as it is no different from the code of the previous tutorial except I have thrown in an extra call to WriteFile to output the user prompt message and a ReadFile, to read some user input into the input_string buffer.

The three lines from the start_loop label are as they have been as well. Now we have the first of our new instructions - the lea instruction which means load the effective address. In this code, we are saying load the effective address of the esi register plus the edi register and place into the eax register. Then push that address onto the stack. What we have done, is to compute the offset address of the current character in the array of characters input by the user. Here in this code, the esi register is being used as a base register as it wil remain constant and the edi register is being used as an offset value from that base address.

NOTE: The esi register and the edi register are the only registers that are 'guaranteed' to contain the same values after a Windows API call that they had before the call.

                    lea         eax, [esi+edi]          ; Load the address of the byte to output
                    push        eax                     ; Stack the address of the char we are writing



The line of code immediately after the WriteFile call is

                    dec         edi                     ; Decrement the index field



which decrements the offset value being used to calculate the address of the next character to be output.

The next three lines we have to discuss contain the last two new instructions, namely or and jne. What the code is doing, is loading the byte that is to be output on the next loop into the al register. The or al, al instruction is basically setting the condition code flags based upon the contents of that byte. What we are looking for here is a NULL (binary zero) byte which we placed just before the start of the input_string buffer. The jne instruction is testing to see if the condition code flags have been set to indicate a status of not zero - in other words the al register is not zero. If the result is not zero, then the next instruction to be executed is back at the start_loop label. If we have readed the end of the input, then the next instruction to be executed is the instruction following the jne.

                    mov         al, [esi+edi]           ; Load this previous byte 
                    or          al, al                  ; Set the condition code flags
                    jne         start_loop              ; Jump back to the start of the loop if not end



The final lines of code simply output two newline characters to the console and the program exits.

Results

If you compile and run the code, these are the kind of results you should get

Please enter some text

This is some text to work with

htiw krow ot txet emos si sihT




The next tutorial may be found here

This post has been edited by Martyn.Rae: 06 April 2010 - 09:56 PM


Is This A Good Question/Topic? 2
  • +

Page 1 of 1