Can anyone help me get this program working?
[code]
;; maximum.asm program determines largest number using nasm
;; source: maximum.asm
;; date: 11/30/2003
section .data
data_items dw 3,67,34,222,45,75,54,34,44,33,22,11,66,0
prompt dw "Max value is: "
lenprompt equ $-prompt
section .text
global _start ;must be declared for linker (ld)
_start: ;tell linker entry point
push ebp ; set up stack frame
mov ebp,esp ; ebp is thumb into stack
push ebx
push esi
push edi
mov edi,0 ;index register
mov eax,[data_items+edi+4] ;base addressing + index+ offset
mov ebx,eax ;first item largest into ebx
start_loop:
cmp eax,0 ;check for last item
je loop_exit ; jump to exit if last item
inc edi ; increment index pointing to next value
mov eax,[data_items+edi+4] ; load next value
cmp ebx,eax ; compare largest value with current item
jle start_loop ; if less than or equal loop to beginning
mov ebx,eax ; else store current item into largest-ebx
jmp start_loop ; jump to start of loop
loop_exit:
push ebx ; save max value
output_prompt:
;; output prompt
mov edx,lenprompt ; count of bytes for write syscall
mov ecx,prompt ; pointer to output buffer
mov ebx,1 ; file discriptor 1 (stdout)
mov eax,4 ; syscall write
int 0x80 ; make call
output_value:
;; output value
mov edx,4 ; count of bytes for write syscall
pop ebx ; get max value
mov ecx,ebx ; pointer to output buffer
mov ebx,1 ; file discriptor 1 (stdout)
mov eax,4 ; syscall write
int 0x80
restore_registers:
pop edi ; restore registers
pop esi
pop ebx
mov esp,ebp
pop ebp
mov eax,1 ; exit() syscall
int 0x80 ;call kernel ebx hold return value maximum
[/code]
Comments
Your Nasm command line was not included in the post
or if you're using an IDE, what IDE & what settings ?
So I was not able to assemble your code the way you were assembling it.
I got a simple example code at the end & some code point critiques
that hopefull will help some what?
[code]
data_items dw 3,67,34,222,45,75,54,34,44,33,22,11,66,0
mov edi,0 ;index register
mov eax,[data_items+edi+4] ;base addressing + index+ offset
mov ebx,eax ;first item largest into ebx
[/code]
Your data_items are BYTEs but you've declaired them as DW WORDs,
you're accessing & getting them as Dwords into EAX,
then INC EDI indexes them as if they were bytes 0-255.
So your value accessing needs repair.
Your first access to them skips over the first 4 bytes. EDI+4
so those first 4 aren't part of the data you're checking.
eax,[data_items+edi+4] is a complicated way to access the data
which costs you size & speed,
MOV ESI,data_items ;ESI = offset address of data, then you can
LODSB or LODSW or LODSD to get DS:data_item values in AL or AX or EAX
which also increments ESI 1, 2, or 4 for you automaticlly.
But if you wanted to fix that part of the code, instead of replace it,
you might try this untested code. (you debug it)[code]
data_items DD 3,67,34,222,45,75,54,34,44,33,22,11,66,0 ;DD wastes x4 =bloatware
MOV EDI,data_items ;offset of values, start at beginning of string
XOR ECX,ECX ;recieves largest # of string
JMP SHORT WERK ;git IP over index incrementer
INCIT: ADD EDI,4 ;aim at the next DWORD
WERK: MOV EAX,[EDI] ;git a DWORD from [DS:EDI]
; MOV EAX,[ES:EDI] ;is an uneeded seg over ride =bloatware
OR EAX,EAX ;check for 0
JZ WEDONE
CMP EAX,ECX
JBE INCIT ;if EAX is <= ECX jump
MOV ECX,EAX ;save the largest value in ECX
JMP SHORT INCIT
WEDONE:
;A better code example might look like this:
data_items DB 3,67,34,222,45,75,54,34,44,33,22,11,66,0 ;DB = Don't Bloat
MOV ESI,data_items ;offset of values, start at beginning of string
XOR ECX,ECX ;recieves largest # of string
XOR EAX,EAX ;zero extended word & AH for later
GITONE: LODSB ;git a byte in AL (DD & LODSD might work 4U)
OR EAX,EAX ;check for 0
JZ WEDONE
CMP EAX,ECX
JBE GITONE ;if EAX is <= ECX jump
MOV ECX,EAX ;save the largest value in ECX
JMP SHORT GITONE
WEDONE:
[/code]
So EDI or ESI is all you need for an index offset pointer.
Nasm discount cheepo poor mans structs are: offset+offset+offset+etc
and each time you add +offsets that can't be computed by the assembler,
it has to be computed at run time and that adds size & is slow =bloatware.
REG+IMMEDIATE can't be computed by the assembler?
IMMEDIATE+IMMEDIATE can be.
Immediates don't change in size in a way the assembler can't keep track of it.
You can reassign a value to a label but the assembler isn't tricked.
So your MOV EAX,[ES:data_items+EDI+4] was just about as complicated as is
possible to make it, and MOV EAX,[EDI] works better. DS is the default segment.
[code]
data_items dw 3,67,34,222,45,75,54,34,44,33,22,11,66,0
mov edi,data_items ;index ptr
mov eax,[edi] ;base addressing
[/code]
The code above makes EAX as follows,
AL = 3 first byte
AH = 67 2ond byte
34 = EAX 3rd byte
222 = EAX hi byte
so EAX = 0xDE224303 & that's a bunch.
In Nasm the size of the destination reg sets the size of the value that is
moved into it. In this case EAX is a DWORD & that's what it gets.
MOV DESTINATION,SOURCE is how it works.
The rest of your code goes like this:
PRINT STRING ok, I take it that this works.
but then you try to print the value of the largest number in your string
as if it was a character 0-255. You need a procedure to print your value in
ASCII text numerical form to std out?
I have included some simple Nasm .asm .com code that finds the largest value
in a nul ending string, then prints the value in ASCII text to std out.
It has a proc you might be able to use: WDECEAX.INC
It assembled to 131 bytes & uses 8, 16, & 32 bit registers
[code]
;assemble with
;NASM -f bin MAXVALUE.asm -o MAXVALUE.com
BITS 16 ;= default address size, use 16 or 32 bit registers.
ORG 100h ; PSP header ends & .COM code starts here
JMP START ; jump over data & procedures
MSG DB "Max value is: "
MSGlen EQU $-MSG
DB 36 ;end of string char = '$'
VALUES DB 3,67,34,222,45,75,54,34,44,33,22,11,66,0
; PROC WDECEAX.INC = Write the DECimal value of EAX to standard out.
; Call with, EAX=value to print in ASCII decimal
; Returns, no regs
align 16
WDECEAX:
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
XOR CX,CX ; clear the push count register
MOV EBX,10
WDEC1: XOR EDX,EDX ; clear the upper Dword & DX = reg to push
DIV EBX ; divide EDX:EAX by EBX=10
ADD DX,48 ; make remainder number a printable ASCII value
PUSH DX ; least siginificant number (remainder) to stack 1st
OR EAX,EAX ; check to see if EAX=input_number is divided to 0 yet
LOOPNE WDEC1 ; get another digit? & this counts the pushes in CX
MOV AH,2 ; function 2, for interupt 21h, write char in DL
NEG CX ; two's compliment, reverse CX (holds push count)
WDEC2: POP DX ; get digit to print, last pushed=most significant
INT 21h ; print ascii interupt 21h ( function 2 in AH )
LOOP WDEC2 ; deincrement CX, write another, if CX=0 we done
MOV DL,13 ; CR carriage return
INT 21h
MOV DL,10 ; LF line feed
INT 21h
POP EDX ;save/restore regs isn't needed in this program
POP ECX
POP EBX
POP EAX
RET
START: MOV AH,9 ;print message to $
MOV DX,MSG
INT 21h
MOV SI,VALUES ;find the largest value
XOR ECX,ECX ;reciever
ZZTOP: LODSB
OR AL,AL ;check for 0=zero
JZ PRINT ;exit loop if 0=nul ending is found
CMP AL,CL
JB ZZTOP
MOV CL,AL ;if AL > CL, MOV CL=AL
JMP SHORT ZZTOP ;loops end
PRINT: MOV EAX,ECX ;print the largest# in ASCII text to std out
CALL WDECEAX ;print EAX
MOV AH,8 ;pause
INT 21h
MOV AX,4C00h ;exit program
INT 21h
[/code]
[green]
You wern't far off, a quickie data accessing fix and a printer proc
was the fix? But I went overboard & covered everything I could think of.
I hope it helps somehow. Do you want a bunch of free Nasm procedures ?
http://bitdog.home.att.net/files/nasmenv.zip
[/green]