Jump to content

Check out our Community Blogs

Register and join over 40,000 other developers!

Recent Status Updates

View All Updates

- - - - -

Intro to Intel Assembly Language: Part 3


  • Please log in to reply
4 replies to this topic

#1 dargueta


    I chown trolls.

  • Moderator
  • 4854 posts
  • Programming Language:C, Java, C++, PHP, Python, JavaScript, Perl, Assembly, Bash, Others
  • Learning:Objective-C

Posted 01 October 2009 - 05:52 PM

Hopefully you've read my previous two tutorials before coming here, otherwise you may be lost. So I've decided to teach you a little bit more than just moving bytes around in memory - now we'll actually accomplish something useful! Still no "Hello, World!" program, though.

There are many instructions we can use to do regular arithmetic, but I'll just teach you the basic ones for now. They are add, sub, mul, div, inc, dec, and neg. Guess what they do.
There's one thing that you need to know about all these instructions, though: the result is stored in the destination operand. So something like: add eax,ecx is the same as eax += ecx. Same with all the others.

MUL - Unsigned Multiplication
This instruction takes only one operand, and assumes AX/AX:DX/EAX:EDX/RAX:RDX as the destination operand. Yes, it clobbers [E/R]DX on 16-, 32-, and 64-bit multiplications. The reason is this: let's say you have 0xFF in AL and you want to multiply that by 0x80. Clearly if we restrict the result to AL it's going to overflow and give an inaccurate result. So 8-bit multiplication gives a 16-bit result. Naturally 16-bit multiplication would yield a 32-bit result, and so on. But why not just use EAX instead of AX for the low word and DX for the high word? Well, back in the old days, they only had 16-bit registers, so the designers were forced to use two registers. When the 80386--the first 32-bit Intel processor--came out, there were still a lot of 16-bit applications out there, so backwards compatibility was a must. Hence 16-bit multiplications on a 32-bit system still use AX:DX. The EAX:EDX and RAX:RDX issue is the same thing.

; al *= cl
;result stored in ax
mul    cl

;ax *= cx
;dx contains high word of result,
;ax contains low word
mul    cx

;eax *= ecx
;edx contains high dword, ax low dword
mul    ecx

DIV - Unsigned Division
div works exactly like mul, except it uses AH/DX/EDX/RDX to store the remainder (i.e. modulus) of the result of the division. So if I were to do this:

mov    al,5
mov    cl,2
div    cl
the result is al=2 and ah = 1. If I were to have assigned ax=5 and cx=2, and divided ax, then the result would be ax=2 and dx=1. Get it?

IMUL & IDIV - Signed Multiplication & Division
Exactly the same except the operands are treated as if they were signed integers.

A Note About Multiplication and Division
Multiplication and division are SLOW. Use a combination of shifting and adding if you can. For example, if you want to multiply AX by 256, don't use mul. Use shl ax,8.

These are relatively straightforward. add a,b is the same as a += b, and sub a,b is the same as a -= b. You can pretty much use whatever operands you want for these instructions (though remember we can't have two memory operands). If an addition overflows, the overflow flag (OF) is set in the flags register; these instructions don't use additional registers to catch the overflow value.

These are used to increment and decrement a memory location or a register. If you specify a memory location, you have to specify the size as well, since there's no other way to figure out what size integer you mean:

inc    DWORD PTR [eax]
dec    BYTE PTR [0x000138E0]

Warning: Due to a change in instruction encoding, you cannot use the inc and dec instructions in 64-bit code. You have to use add OPERAND, 1. I'm not going to get into why unless someone asks me, as it's somewhat complicated especially for someone who's at this stage in learning ASM. Just take my word for it for now.

NEG - Negate an Integer
Well...it negates an operand. Same as a = -a. Like the inc and dec instructions, you have to specify the size when you pass memory operands; unlike inc and dec, you can use this instruction in 64-bit mode.

I'm only going to teach you basic jumping for now; conditional jumping will come a bit later. This is the equivalent of the abhorred goto statement in higher-level languages. Unlike higher-level languages, however, it's a necessary component for creating if-elseif-else and switch blocks, and for, while, and do-while loops to a certain degree as well. The syntax is easy:

;jump to a specific label. this is the most common
;as the compiler handles figuring out the actual
;addresses for you.
jmp    <label>

;jump to a hard-coded address
;segment 0x1941 offset 0x000000F0
jmp    0x1941:0x000000F0

;assume eax contains the address of a pointer. it can
;either be a short pointer (i.e. you can only jump
;within your current segment), or a long pointer, in
;which case you can jump to any offset in another
;segment. either way you need to specify.
jmp    near [eax]
jmp    far   [eax]

Putting It All Together
Here's a useless program in C:
a = 5;
b = 10;
a += b;
//a now equals 15
a = -a;
//a now equals -15
b += a;
//b now equals -5;
b *= a;
//b now equals 50.
//a now equals -16
goto some_place;
and here's the equivalent ASM, with AX for a and BX for b.
mov    ax, 5
mov    bx, 10
add    ax, bx
neg    ax
add    bx, ax
;uh-oh...we want to multiply bx but we have the values in
;the wrong registers for that...let's swap them.
xchg   ax,bx
;now a=bx and b=ax. let's multiply...
mul    bx
;swap them back so a=ax and b=bx
xchg   ax,bx
;continue on with life.
dec    ax
;alternatively, if running on a 64-bit processor, we would
;have do do    sub    ax,1.

;now jump somewhere...
jmp    ES:[EDX]

Well, that's all for today. Hope you've found this informative!

Next In This Series

Edited by dargueta, 18 November 2010 - 07:18 PM.
Fixed syntax error

  • 3

sudo rm -rf / && echo $'Sanitize your inputs!'

#2 Guest_Jordan_*

  • Guest

Posted 02 October 2009 - 05:23 AM

Very well done and presented! +rep
  • 0

#3 WingedPanther73


    A spammer's worst nightmare

  • Moderator
  • 17757 posts
  • Location:Upstate, South Carolina
  • Programming Language:C, C++, PL/SQL, Delphi/Object Pascal, Pascal, Transact-SQL, Others
  • Learning:Java, C#, PHP, JavaScript, Lisp, Fortran, Haskell, Others

Posted 02 October 2009 - 07:42 AM

Very informative. It's a great example of how assembly can do everything the other languages can do (duh!), but it forces you to think at a slightly lower level. +rep
  • 0

Programming is a branch of mathematics.
My CodeCall Blog | My Personal Blog

My MineCraft server site: http://banishedwings.enjin.com/

#4 debtboy


    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 499 posts

Posted 02 October 2009 - 08:10 AM

Great Tutorial +rep
  • 0

#5 dargueta


    I chown trolls.

  • Moderator
  • 4854 posts
  • Programming Language:C, Java, C++, PHP, Python, JavaScript, Perl, Assembly, Bash, Others
  • Learning:Objective-C

Posted 08 October 2009 - 11:52 PM

Thanks, guys! I'll try to keep these coming, but unfortunately they're probably going to be further apart than before. (Read: school is taking over my life.)
  • 0

sudo rm -rf / && echo $'Sanitize your inputs!'

Also tagged with one or more of these keywords: assembly

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download