Hello, peoples. I'm noobish here... and once again, I must join a forum by asking a question, then finding out I placed it in the wrong area and worded it poorly, thus getting no acceptable answers... But this time might be an exception!  :O

So I'm noobish to Assembly, and I've found a lacking of information elsewhere on the Internet, and got redirected to here by a person. I'm using the NASM assembler, and... it appears as though it isn't popularly used... but it seems I can't find any downloads for any other assemblers, and I've grown too attached to NASM by now, anyways...

I've found just about 0 tutorials going anywhere beyond absolute basics. It seems I can find nothing about variables, and nothing about arrays. But.. that's only partially what I mainly wanted to ask. I figured a calculator could prove to be a good example, though, because it'd require everything I'm wanting to know.. I think...

SO, basically, how would user input be stored in a character array? Like, if I type 'a', will that, then, be added to the end of the array, then continue down the process? Are there other, simpler ways of doing this? And how would I declare the existence of this array?
And.. how would I take this string and add something to it? If I would type in '5', then try adding the next user inputted character, '2', the result would be 'g'.
Similarly, if I take '5' and '2', convert them both to plain integers, then add them together, how do I turn them back into a string? I made a thing which gets the current year, and it threw '?' at me as the answer. Surely that's not this year :/  (But then again, my computer's clock doesn't like staying set quite right, so I'm usually a little ahead of everyone else ^.^  Sometimes days ahead, sometimes years ahead...)

And then the easy part is manageable from there... but I'm clueless, and have been searching the Internet for over a week... Help is greatly appreciated.
Thank-you in advance to any answers. (if you can figure out where this question should have been placed, and what my incoherent sentences were meant to say)

(and note that I'm generally tired and with a severe lacking of sleep, so... actual code for this would be helpful, and preferably with some explanation that's relatively straightforward... I'm braindead... like, all the time >.<)
Posted on 2010-03-10 01:53:10 by Nikumu
^ I notice a lack of an 'edit' button... so sorry for double posting...

Sorry if there's already a topic regarding this subject - I found none in my search, thus quickly resigned in my weakness and inability to continue.
Posted on 2010-03-10 01:58:41 by Nikumu
First of all: Which assembler? what hardware? which OS?
Posted on 2010-03-10 12:02:10 by ti_mo_n

First of all: Which assembler? what hardware? which OS?


Haha... I dunno how readable that is at all, as a later statement I tried writing... turned out... horribly.. And I remembered that I probably should have stated these shortly after posting this.

NASM Assmbler, Windows XP, and 8086.
Posted on 2010-03-10 13:38:28 by Nikumu

Hello, peoples. I'm noobish here... and once again, I must join a forum by asking a question, then finding out I placed it in the wrong area and worded it poorly, thus getting no acceptable answers... But this time might be an exception!  :O


Eric Raymond has some thoughts about how to ask questions so that the experts will want to help you...

http://catb.org/~esr/faqs/smart-questions.html


So I'm noobish to Assembly, and I've found a lacking of information elsewhere on the Internet, and got redirected to here by a person. I'm using the NASM assembler, and... it appears as though it isn't popularly used...


We're in the Top 40. With a bullet! :)


but it seems I can't find any downloads for any other assemblers, and I've grown too attached to NASM by now, anyways...


It's too late to stop now! :)

There are plenty of other assemblers. We can hook you up with a download site,  I'm sure, if that's what you want, but I don't think it'll help (they all do the same thing, essentially).

FWIW, Nasm 2.08 has just been released - http://www.nasm.us - but the bad news is that a minor glitch has been found in it already - 2.08.01 will be along soon.


I've found just about 0 tutorials going anywhere beyond absolute basics. It seems I can find nothing about variables, and nothing about arrays.


http://www.drpaulcarter.com/pcasm - quite an extensive chapter on arrays...


But.. that's only partially what I mainly wanted to ask. I figured a calculator could prove to be a good example, though, because it'd require everything I'm wanting to know.. I think...

SO, basically, how would user input be stored in a character array?



mov , al
inc edi


...or so, probably. Getting the input depends on your OS.


Like, if I type 'a', will that, then, be added to the end of the array, then continue down the process? Are there other, simpler ways of doing this?


Any OS will have an input function. "sys_read" for Linux. You mention XP - "ReadFile", but you'll have to do "GetStdHandle" first. But you mention 8086 too. That makes me think maybe you're doing dos - int 21h/0Ah.


And how would I declare the existence of this array?



section .bss
input_buffer resb MAX_INPUT + 1


...maybe?


And.. how would I take this string and add something to it? If I would type in '5', then try adding the next user inputted character, '2', the result would be 'g'.


Yeah... adding characters doesn't work well.


Similarly, if I take '5' and '2', convert them both to plain integers, then add them together, how do I turn them back into a string?


Ah! So you do know that you need to do this! Many tutorials relegate this to a macro, or provide a library call (Dr. Carter  resorts to "just call printf"... and the horrid scanf, for these chores). Personally, I think it's an educational exercise to attempt. You're putting together a series of simple-minded instructions to do something "useful" - with a visible result, and it isn't likely to do damage if you get it wrong. So I urge you to give it a shot, and see what you come up with.

If you need some hints, search for something like "convert string to number", "convert number to string", "how do I print a number", "get number from keyboard", etc. If you don't find anything here (I'm sure you will - it is a very frequently asked question!), hop over to the new Nasm forum - http://forum.nasm.us - (supplants the Nasm forum at SourceForge, which has been "improved" so much that it's totally unusable. IMHO...). I know for a fact that there has been discussion of the subject in recent threads. :)

Google groups - alt.lang.asm and comp.lang.asm.x86 would find info on the subject, as well.


I made a thing which gets the current year, and it threw '?' at me as the answer. Surely that's not this year :/


I wouldn't count on that. I'm 65, and every year so far has been '?'. :)

You don't say how you were getting the year. Linux gives us seconds since "the dawn of time" - 01/01/1970. The bios interrupt (if you're doing dos) returns the values in BCD, as I recall (Binary Coded Decimal). If that's the case, try printing it as if it were hex.

Show it to us! We can probably help you fix it.


(But then again, my computer's clock doesn't like staying set quite right, so I'm usually a little ahead of everyone else ^.^  Sometimes days ahead, sometimes years ahead...)


So how come you're not showing us how to do it? :)

Best,
Frank

Posted on 2010-03-11 03:07:53 by fbkotler
Thank-you for the reply :)
Hmmm.... my question was worded rather poorly, and thus I apologize. :) 



So, thus far I seem to have come up with this:


org 100h

section .bss
x resb 10h
y resb 10h

section .text

start:
mov dx,msg1
mov ah,09h
int 21h

mov ah,01h  ; Input x
int 21h
sub al,30h
mov ,al

mov dx,newl  ; New line
mov ah,09h
int 21h

mov dx,msg2  ; Print msg2
mov ah,09h
int 21h

mov ah,01h  ; Input y
int 21h
sub al,30h
add al,  ; Add x+y
mov ,al

mov dx,newl  ; New line
mov ah,09h
int 21h

mov dx,msg3  ; Print msg3
mov ah,09h
int 21h

mov bx,  ; Print the result
add bx,30h
mov dx,bx
mov ah,06h
int 21h

mov ah,07h  ; Pause
int 21h
mov ah,4Ch
int 21h

msg1 db 'Enter a number',0Ah,0Dh,' -->  $'
msg2 db 'Enter another number',0Ah,0Dh,' -->  $'
msg3 db 'The answer is: ',0Dh,0Ah,' -->  $'
newl db 0Ah,0Dh,24h


Although this has multiple faults:
Neither x or y can hold more then one character (easily fixable)
The result can be no greater than 9, lest various characters be thrown out

I'm thinking that I know how to convert a string to a number now.. so that's of minimal priority. Find the string length, subtract 48 from each character, and then multiply accordingly; if I entered '145', take away 48 from each character, then multiply the 1 by 100, 4 by 10, and 5 by 1, and add them all together into one number.

But... then I'm still rather clueless as to how to do the same thing in reverse..... I read on.. somewhere (I seem to have exited the tab)  that it can be done by doing the same thing in reverse: repeatedly dividing by ten, then adding the remainder to the end of the end of an array. But... the 'div' is confusing me... thus far I've failed to get it to work. (it's all of NASM's fault - it's just not cooperating; I have naught to do with this)  How does div work?


mov dx,8
mov ax,2
div ax

is the best I've come up with, and it keeps returning 1 (or, rather, a mocking smiley face O.o). Clearly I'm not using it correctly... But, what is the proper usage? I'm left clueless and dumbfounded once more... and my mad Googling skillz are failing me... (pretty epic... the searches that seem to meet the best results are the ones questioning the purpose of features of cats; "why do cats purr", "why do cats have tails", etc.)

Or am I mistaken in saying that dividing in the above named manner would work?


"You don't say how you were getting the year. Linux gives us seconds since "the dawn of time" - 01/01/1970. The bios interrupt (if you're doing dos) returns the values in BCD, as I recall (Binary Coded Decimal). If that's the case, try printing it as if it were hex.

Show it to us! We can probably help you fix it."

(I don't have immediate access to how the quotes work here, so... I'll just be inconvenient and leave it in normal quotation marks)


mov ah,2Ah
int 21h
mov dx,al
mov ah,09h
int 21h

(apparently a normal and thus expected number of characters show up here; 0x07DA, or, 2010 doesn't O.o )
That would be (basically) how it was done;

Yeah - all that would need to be done is converting this to a sort of string. (I think....)  "Printing it as if it were hex"? How's this done? Or perhaps a better question... What is this? (wouldn't have been the first time I crashed my computer because I asked "how" before "why" :P )


"So how come you're not showing us how to do it? :)"
I tend to forget a lot upon the shock of realizing that I've been sitting at the computer for the past 16 years, 10 days, and an hour... time flies with glitchy clocks... my proof: I've been typing this for the past 14 days according to this clock


Thank, again, for answering! (I've been trying to determine the general answer to this for over two weeks)
Posted on 2010-03-11 21:51:57 by Nikumu
You've really got two different questions here. The "year" one is probably easier... maybe...

("quote", incidentally is done like "code" - "quote" and "/quote" in "[]"s - so it seems - lemme try it)



mov ah,2Ah
int 21h
mov dx,al
mov ah,09h
int 21h



You're fibbin' to me, Nikumu! Nasm won't assemble that! "mov dx, al"? No way! "movzx" maybe. But it isn't what you want, in any case. Ralf Brown...

http://www.ctyme.com/intr/rb-2686.htm

(if you don't know Ralf, he's your new best friend!) says int 21h/2Ah returns the year in cx. So we either write a function that converts cx to text, or...


mov ah, 2Ah
int 21h
mov ax, cx ; year
call showax
ret


The "showax" function gets us right back into the other question, "how do I print a number?" which rapidly decomposes into "div???". You tried:



mov dx,8
mov ax,2
div ax



Just about the worst thing you could have done, as it turns out. :) "div", in the size we're talking about, uses ax and dx as implicit operands - we don't have any choice about 'em. dx:ax (that is, dx times 65536 plus ax) is divided by... a register or memory that we provide. I'm surprised that what you tried didn't crash your machine (doesn't hurt it - good exercise!), 'cause if the result doesn't fit in ax, it raises an exception. 8 times 64k plus 2, divided by 2, shouldn't.

See what the old Nasm manual had to say about "div":

http://home.myfairpoint.net/fbkotler/nasmdocc.html#section-A.4.59

In our case, we want dx to be explicitly zero, since we "don't care" about it, and the CPU does. We could put 10 in a register, or in memory - "div 10" won't work. :(

After the "div", the quotient is in ax (we probably want to keep it to use again), and the remainder is in dx (so we're going to have to zero it again for the next "div"!). This is one of the digits we're looking for. Since we've divided by ten, it'll be between 0 and 9, so it'll fit in dl. We can just "add dl, '0'", to "convert" to a character, which we can store in a buffer. If we put a '$' as the very last thing in the buffer, and worked forward from there, we could display it with int 21h/9...

There are different ways to do it - "div" is quite slow. A repeated subtraction version can actually be faster(!). The fastest version involves multiplying by the reciprocal of 10... I think... makes my head hurt to try to figure it out. "div" is "fast enough", I guess. :)

The attached code displays ax as decimal, hex, and binary (let's see "just call printf" do that!). It is horribly slow - calls the OS for each character - much faster to accumulate the characters and just call the OS once! It is fairly well "explained", I think - far better than any "calculator" code I'd have around! You can do better, but maybe it'll give you an idea how to get started...

Best,
Frank

Attachments:
Posted on 2010-03-12 03:45:05 by fbkotler

You're fibbin' to me, Nikumu! Nasm won't assemble that! "mov dx, al"? No way! "movzx" maybe. But it isn't what you want, in any case.


Oh... I meant 'mov dx,cx'. I guess I typed 'al' forgetting what I was doing at the moment. (after all, I am unable to make mistakes unless I have my memory to blame)


Just about the worst thing you could have done, as it turns out. :)


I try my hardest - after all, if I only did something minutely wrong, I could never find where my mistake was. ;)


So... I have pretty much everything for this calculator made...


contonum:
 
.beg:
  call topower ; Yes, Civilization: Call to Power
 
  mov dx,
  sub dx,30h
  mul dx
  add bx,ax
 
  cmp cx,00h
  je .end
 
  dec cx
  jmp .beg  ; I think this is all how it was before I did some editing to it..
 
.end:
  mov ax,bx
  ret



topower:
  push bx
  push cx
  mov ax,1
  mov bx,10
 
  cmp cx,0
  je .if1
  jne .beg
 
.if1:
  mov ax,1
  jmp .end

.beg:
  mul bx
  dec cx
  cmp cx,0
  je .end
  jne .beg

.end:
  pop cx
  pop bx
 
  ret

Is what I have so far of the conversion of characters to numbers.... although this is harder than I had anticipated.

Somewhere in 'contonum' (convert to number), there is a mistake. Where it is, I've not yet pinpointed.

Although I'm pretty sure it's still doable. I'll separate it later (I'm brain-dead now; I've basically been writing two small parts of this calculator at a very sluggish rate, all day...)  and try to get it...
But... if I would make input be done through 0Ah/21h, could I still go through that and grab specific characters? Like, is it possible to do something like 'mov ,otherregister'?


In what I'm using at the moment:


gets:
  push ax
  push cx
 
  xor bx,bx

.beg:
  mov ah,07h
  int 21h
  cmp al,0Dh
  je .end
 
  mov ,al
  inc bx
  jmp .beg

.end:
  pop cx
  pop ax
 
  ret


is it possible to make it possible to move the contents of 'al' into 'dx', so that they can be left undestroyed upon being taken back out of x? (that was a poorly crafted sentence... but I know not how to make it better, and I know not how to rephrase it...)
I think what I tried doing there is the same thing as I had tried doing with the clock, isn't it?...

I think I'm gonna conclude writing (typing)  this quickly, hoping I don't neglect to say anything... I suddenly realized that I need to disappear from here.

So the 'contonum' mistake, I'm pretty sure, was made when I started being careless and just throwing what I thought might fix it in. If help is attempted to be provided for that, I'll cover my ears and start screaming. (hopefully in your annoyance at me for doing this, you won't notice that my eyes are still open and I'm reading the help)

But... I think my only still-standing question is how to movement of things from specific areas in 'dx' is done, and/or how I might move things from al to dx...

Thus far I've learned infinitely more than I had prior known... but I still remember it being easier in C...

(note that I'm unsure that all the code I used there is exactly how I wanted it... I might have changed some of it around to try seperating various other mistakes, out of the millions of ones that were initially there, and not noticed when copying/pasting it here)
Posted on 2010-03-13 18:55:24 by Nikumu
Of course it's easier in C. Someone else has already written the code for you! Try it without any library calls. Quite possible, and if you still find it easy, you might work out the algorithm in C, and "translate" to asm. (or just let the compiler do it, and forget asm...)


contonum:
 
.beg:
  call topower ; Yes, Civilization: Call to Power
 
  mov dx,
  sub dx,30h
  mul dx
  add bx,ax


Okay... it might be nice to comment this code to divulge that the string length is in cx. (right?). So "topower" returns with ax at 10000, 1000, 100, 10, or 1, depending on the length of the string. (right?) Looks like it would work.

I take it that "x" is the input buffer where the user has put some characters representing decimal digits. (or some other garbage - pesky users!) I'm not sure what's in bx - zero, initially? In any case, you're getting two characters (or two bytes, at least) into dx. This is not what you want. Probably just use dl, here. But you are going to want to multiply by dx! What to do? "mov dh, 0" would fix it. "movzx dx, byte " would do it. "xor dx, dx" (before "mov dl, "!). Pick your favorite.

You multiply by whatever "topower" gave us, and add the result to... whatever was in bx. Okay if bx was "result so far", but you loop back to ".beg:"... What in heck does "" point to now? I think you need to introduce another register here - one to serve as "result so far" (should probably be explicitly zeroed before we start), and another to index into the buffer at "x".

That should work, but I would do it a slightly different way, which doesn't need to know the string length, or "whatpower"...

; zero a register for "result so far"
.top:
; get a character, one way or another
; verify it's a valid digit (if not, quit, or ignore and continue? - if CR, quit)
; multiply "result so far" by ten
; add in the new digit, converted from character to number
; go back to .top

Here's a cute way to do it:


atoi:
    mov edx,   ; pointer to string
    xor eax, eax        ; clear "result"
.top:
    movzx ecx, byte
    inc edx
    cmp ecx, byte '0'
    jb .done
    cmp ecx, byte '9'
    ja .done
   
    ; we have a valid character - multiply
    ; result-so-far by 10, subtract '0'
    ; from the character to convert it to
    ; a number, and add it to result.
   
    lea eax,
    lea eax,

    jmp short .top
.done
    ret


Using the two "lea"s to do the whole multiply-by-ten-etc was generated by a compiler(!). It is essentially "C code", which must preserve ebx, esi, edi, etc... so it doesn't use any of them. C is allowed to "trash" ecx and edx, so it does. But these registers aren't really "trash" - edx is "next position in string", and cl is the invalid character that ended input. If we're calling this from asm instead of C, we can utilize this information. Note that while I called it "atoi", it deals with unsigned integers - should really be called "atou". Since "lea" doesn't set flags, we have no way of detecting overflow.

You ask, "is it possible to do something like 'mov ,otherregister'?"

No, not exactly. 16-bit addressing modes are picky, picky, picky! You can do "mov , al" or "mov , al" but not "mov , al". You can do "mov , al", even in 16-bit code, but the upper bits of edx must be clear. Usually, this is true, but there are exceptions - such as after running a DJGPP build of Nasm(!). (ask me how long it took me to figure that bug out!) If you're planning to use 32-bit registers in 16-bit code, I would "xor edx, edx" for each register you're going to use, right at the beginning of the program, "just to be sure". (this means that "atoi" above would "probably" work in 16-bit code... have to "push dword buffer" and "add sp, 4" after... never tried it...)

To do it in 16-bit instructions, you may have to juggle registers around a bit. Lemme see...


org 100h

%define MAX_INPUT 5
section .bss
input_buffer resb MAX_INPUT + 3

section .text
; prep the buffer for int 21h/0Ah
mov word , MAX_INPUT + 1

; prompt?
; get the number
mov dx, input_buffer
mov ah, 0Ah
int 21h

mov cl,
mov ch, 0
; now cx is string length, if you want it

; convert the text to number
mov si, input_buffer + 2
xor bx, bx
.top:
lodsb  ; "mov al, "/"inc si" - all in one byte!
cmp al, 10 ; or 13 for dos???
jz .done
sub al, '0'
jc .invalid
cmp al, 9
ja .invalid
imul bx, bx, 10
; jc .overflow
mov ah, 0 ; just to be sure
add bx, ax
; jc .overflow
jmp short .top
. done:
.invalid:  ; do something special here, if you want
mov ax, bx
;ret ; oops, we weren't called
; ...


(caution: untested code!)

There ya go, now just press the square root key, and...

Your "gets" looks good (does it "echo" what you type?), but it looks like "gets" - allows buffer overrun - extremely bad!!! Throw it out, or rework it to "ngets" (limit input to the length of your buffer). Sorry to be a nut-case about "gets", but... every time a new version of comes out, it's full of buffer overruns that vile individuals exploit, causing trouble for all of us. This is not a new problem, but the "professionals" can't seem to figure it out. Us hobbyists have gotta do better. Please don't use "gets"!

Best,
Frank

Posted on 2010-03-14 09:29:34 by fbkotler

Okay... it might be nice to comment this code to divulge that the string length is in cx. (right?). So "topower" returns with ax at 10000, 1000, 100, 10, or 1, depending on the length of the string. (right?) Looks like it would work.


Yeah, x is input buffer; I suppose I should have left comments... I'm not used to having to do that, but I'm thinking it'll be more necessary in Assembly... right. And yes; cx = string length.


I think I had some sort of pop/push thing before and after the increment of bx, as I couldn't think of enough registers that would work at the time. bx served as both the current position to read, and and result so far... of course that doesn't appear to have been working so very perfectly...


That idea does seem a bit easier...

I tried doing this:

contonum:
  xor ecx,ecx        ; Current Position in x
  mov ax,10
  xor bx,bx
 
.beg:
  movzx dx,  ; Get the cx position in the input buffer
 
  cmp dx,'9'
  ja .end
  cmp dx,'0'
  jb .end
 
  mul bx          ; Multiply bx by 10, then add the next number to it...
  sub dx,30h
  add bx,dx        ; This is where the problem is?
 
  inc ecx
 
  jmp .beg
 
.end:
  ret


And that throws out a number that... obviously does not equal the 32 I'm wanting it to...


call contonum
  mov ax,bx
  call contochar


Is where it got called.


I tried using the above provided code, but quickly encountered the problem of moving eax into ax. 'movzx' does that the other way around, but... is it also doable as eax>ax in any way?


; I appear to have closed the Notepad where is was being kept... or something..... so this is untested, and rewritten...

atoi:
    mov edx,   ; pointer to string
    xor eax, eax        ; clear "result"
    xor ebx,10
.top:
    movzx ecx, byte
    inc edx
    cmp ecx, byte '0'
    jb .done
    cmp ecx, byte '9'
    ja .done

    mul ebx
    sub ecx,30h
    add ebx,ecx
   
    lea eax,
    lea eax,

Is what would finish that? But then, what exactly does 'movzx ecx, byte ' do? Is edx where the last byte read is?
'mov edx, ' also leaves me..... umm... (I'll think of a word...)... without knowing what's going on..... (I know a fancy word for that, but what is it? >.<)

I don't think that was as concise as 'twas planned, was it? But that is still well..... But I think (and have said before) that eax>ax may be the answer to all my problems, as is it to the rest of the world's problems. But... then, we'll find out what problem I next encounter.... there are infinite, just waiting......... Is that all I meant to say..... I dunno...... but I'm being rushed again today, and think it should be, regardless of whether or not it really is :/ 
Posted on 2010-03-16 16:00:37 by Nikumu
If there are set bits in the upper word of eax, "eax>ax" isn't going to "fit". We'll have to assume that the upper word of eax is clear - or meaningless to us - in which case we just use ax. If that solves all the world's problems, we're in good shape! :)


'mov edx, ' also leaves me..... umm...


I shouldn't have shown you that. The "string" is passed to the subroutine by pushing it on the stack, before "call"ing the function. In 32-bit code, "call" stores a 32-bit (4 byte) return address on the stack, so our parameter is at . In 16-bit code, "call" would only use 16 bits, so that wouldn't be right. Shouldn't have showed it to you - forget 32-bit...

You've got a "problem" in a couple of your code examples, in that "mul" uses dx as one of its destination registers, trashing whatever you had there - pointer-to-string in one case (replacing the "two lea trick" with a regular "mul" totally breaks that code!) , and "the byte" in the other.


I tried doing this:


contonum:
  xor ecx,ecx        ; Current Position in x
  mov ax,10
  xor bx,bx
 
.beg:
  movzx dx,  ; Get the cx position in the input buffer
 
  cmp dx,'9'
  ja .end
  cmp dx,'0'
  jb .end
 
push dx ; save "the byte" - "mul" is going to trash it!

  mul bx          ; Multiply bx by 10, then add the next number to it...

pop dx ; get our character back
mov bx, ax  ; "mul" left the answer in ax, not bx!
mov ax, 10  ; get ax back where we want it


  sub dx,30h
  add bx,dx        ; This is where the problem is?
 
  inc ecx
 
  jmp .beg
 
.end:
  ret



Untested, but I think those changes will fix it. Obviously(?), the rigamarole to clean up the mess made by "mul" could be reduced by different choice of registers.

Using 16-bit registers "" won't work, but bx, si, or di would. "mul" uses ax and dx as destination registers (dx * 65536 + ax). If dx is non-zero, you've overflowed 16 bits with your number. You may want to check for this. You should have enough registers to do this, if you choose 'em wisely.

"imul" is a funny instruction. It's actually two very different instructions... made to look like three.


imul bx


works like "mul" - a 16-bit by 16-bit multiply into a 32-bit result (bx * ax -> dx:ax). The difference is that "imul" works for signed integers, and "mul" works for unsigned.


imul cx, bx, 10


is different. It does a 16-bit by 16-bit multiply, into a 16-bit result (bx * 10 -> cx). Any overflow out of 16 bits is lost. It also accepts an "immediate" operand, as well as the reg or the other forms require. Handy!


imul bx, 10


is the same instruction as "imul bx, bx, 10", with source and destination the same register. So the two-operand form is just a special case of the three-operand form.

If you find that confusing, go back to "mul", but being able to write "10" instead of having it in a register ("ten dw 10"..."mul word " will work, too) might free up a register...

Best,
Frank

Posted on 2010-03-16 23:37:37 by fbkotler
fbkotler"]It also accepts an "immediate" operand, as well as the reg or the other forms require. Handy!


I beg to differ. For three-operand imul, destination is always register, and one of the multiplicands (third operand) is always immediate.
Posted on 2010-03-17 12:00:39 by baldr
Right you are. Only the two-operand form gives us a choice. I guess it really *is* three different instructions. Thanks for the correction!

Best,
Frank



Posted on 2010-03-17 12:46:30 by fbkotler