views:

68

answers:

2

How do I subtract a decimal value in assembly. IA32 (linux)

1:       mov edx, 1/2   
         sub ecx, ebx
         sub ecx, edx
         mov bal2, ecx

I tried this but it some how skips the subtraction with the decimal. And if I enter .5 it gives me an error.

error:junk `.5' after expression

+2  A: 

The code you provided is not capable of subtracting a "decimal value". I am assuming that by "decimal value" you really mean floating-point value, in which case you can not use the integer arithmetic facilities as you've done.

I highly recommend you download the Intel IA-64 Architecture Software Developer's Manual (Intel IA-64 Architecture Software Developer's Mnaul) and have a read through the sections that explain how to use the x87 floating-point facilities. Specifically, look at:

  • Volume 1, Section 5.2
  • Volume 1, Chapter 8
  • Volume 2A, Section 3.2

As a word of caution, my experience with the floating-point facilities is quite minimal. However, my understanding is that it is a stack based environment in which you can load (push) an item on to the stack and then operate on it. The commands I would look at are: FLD, FSUB, and FST (all are listed in Volume 2A).

As an example, here is a short program that loads +1 and the constant pi into the floating-point stack then performs the operation pi-1 and pops the result.

/* floating point subtraction */

    .text
    .globl _main

_main: pushq %rbp movq %rsp, %rbp

    fld1    /* load +1.0 */
    fldpi   /* load pi (3.14159...) */
    fsubp   /* 3.14159 - 1.0, pop result */

    movq    $0x0, %rax
    leave
    ret
Dean Pucsek
P doesn't pop to *ax, it just frees it from floating point stack.
Jens Björnhager
On the other hand, **movq $0x0, %rax** might just be your return value.
Jens Björnhager
+4  A: 

As lightbulbone correctly says in his answer, you cannot work on floating point values when using general purpose registers (eax etc.). You could use the FPU, as lightbulbone suggests, but that is comparatively tedious.

Alternatively - unless your code needs to run on ancient CPUs - you can use the SSE instructions for this task, which is much more straightforward. Code similar to what you are showing might look like the following:

.data 
  OneHalf dd 0.5
  bal2 dd ?
.code
  movss xmm0, OneHalf  ; instead of mov edx, 1/2
  subss xmm1, xmm2     ; instead of sub ecx, ebx
  subss xmm1, xmm0     ; instead of sub ecx, edx
  movss bal2, xmm1     ; instead of mov bal2, ecx
PhiS