Moving data between registers 
Author Message
 Moving data between registers

I'm writing a function in NASM assembler, which is supposed to be called
within a C program.
The function takes two float arguments. Therefore the first one starts in
[EBP+8] and the second one in [EBP+12].
I need to move 2 bytes of the first argument to register AX and the
following 2 bytes to register DX .
I've tried to do it in the following way.
mov AX, [EBP+8]
mov DX, [EBP+10]

Or I've applied the following method:

mov EAX,[EBP+8]
push EAX
pop AX
pop DX

When I compiled the asm part and C part and put it all together all I got
was

"segmentation fault"

Any ideas?
Best Regards,
Pawe3



Wed, 06 Jul 2005 22:13:16 GMT  
 Moving data between registers

Quote:

> I'm writing a function in NASM assembler, which is supposed to be called
> within a C program.
> The function takes two float arguments. Therefore the first one starts in
> [EBP+8] and the second one in [EBP+12].
> I need to move 2 bytes of the first argument to register AX and the
> following 2 bytes to register DX .
> I've tried to do it in the following way.
> mov AX, [EBP+8]
> mov DX, [EBP+10]

> Or I've applied the following method:

> mov EAX,[EBP+8]
> push EAX
> pop AX
> pop DX

> When I compiled the asm part and C part and put it all together all I got
> was

> "segmentation fault"

Weird! The parts you've posted look okay (either way should work, I
think), I suspect the fault lies elsewhere. Not creating/destroying the
stack-frame correctly, not cleaning up the stack in the C caller,
possibly not saving ebp, ebx, esi, edi across a C call (and "main" is
called, don't forget - but this would only be a problem if your "main"
is in an asm file, I think). Those are things I can think of that would
cause a seg-fault. Maybe there's something wrong with what's shown here,
but I don't see it. If you can't figure it out, post more of the code...

Best,
Frank

P.S. Hmmm, does C "promote" all floats to "double"? That might cause
unexpected results, but shouldn't seg-fault... (?)...



Wed, 06 Jul 2005 23:14:53 GMT  
 Moving data between registers

Quote:
> Weird! The parts you've posted look okay (either way should work, I
> think), I suspect the fault lies elsewhere. Not creating/destroying the
> stack-frame correctly, not cleaning up the stack in the C caller,
> possibly not saving ebp, ebx, esi, edi across a C call (and "main" is
> called, don't forget - but this would only be a problem if your "main"
> is in an asm file, I think). Those are things I can think of that would
> cause a seg-fault. Maybe there's something wrong with what's shown here,
> but I don't see it. If you can't figure it out, post more of the code...

> Best,
> Frank

> P.S. Hmmm, does C "promote" all floats to "double"? That might cause
> unexpected results, but shouldn't seg-fault... (?)...

Well, the C code looks as follows:

#include <stdio.h>
#include <stdlib.h>
float *floatdiv (float *d, float *s); //asm function declaration
int main(int argc, char *argv[]) {
        float *d;
        float *s;
        int liczba;
        *d=atof(argv[1]);
        *s=atof(argv[2]);
        liczba =13;

        printf("d = %f\n", *d);
        printf("s = %f\n", *s);

        printf("result = %X\n", *(long int*)floatdiv(d, s));

        return 0;

Quote:
};

And the NASM code is here:

section .text
global floatdiv
%define d [ebp+8]
%define dHI [ebp+8]
%define dLO [ebp+10]
%define s [ebp+12]

floatdiv:

prolog:
        push ebp
        mov  ebp, esp
        push esi
start:

        mov eax, [ebp+12]
        push eax
        pop dx
        pop ax
epilog:
        pop esi
        pop ebp
        ret

Any conclusions??



Thu, 07 Jul 2005 01:49:21 GMT  
 Moving data between registers

 > Any conclusions??

Yeah, my C sucks. But lemme try it...

Quote:
> float *floatdiv (float *d, float *s); //asm function declaration

Okay, we've got a function that takes two "pointer to float" and returns
"pointer to float"....

Quote:
>         printf("result = %X\n", *(long int*)floatdiv(d, s));

So we call it with pointers to float, and cast the return to "pointer to
long int" - is that going to work?

Quote:
> And the NASM code is here:

> section .text
> global floatdiv
> %define d [ebp+8]
> %define dHI [ebp+8]
> %define dLO [ebp+10]
> %define s [ebp+12]

> floatdiv:

> prolog:
>         push ebp
>         mov  ebp, esp
>         push esi
> start:

>         mov eax, [ebp+12]

This gets us the pointer to float. Wouldn't you need to do:

mov eax, [eax]

or something equivalent?

Quote:
>         push eax
>         pop dx
>         pop ax

I'm assuming you want the two halves of the float here, not its address?

Quote:
> epilog:
>         pop esi

Since you haven't got any local variables, and you balance your pushes
and pops, this should be okay, but I think we usually do:

     mov esp, ebp

Quote:
>         pop ebp
>         ret

... and we return what's in eax - which *was* a pointer to float, before
I screwed it up - better use another register there, I guess. (maybe
"push dword [eax]"/"pop dx"/"pop ax"... no, that'd still{*filter*}up eax...
maybe "mov esi, [ebp + 12]"/"mov eax, [esi]"... and "mov eax, esi" just
before "pop esi"... or... what *is* this supposed to return?)

I dunno, I can see it might return "garbage", but I don't see why it's
seg-faulting. I haven't tried it, obviously. Maybe I'll have to. For
elf, it looks like (no underscore)... I dunno!

Later,
Frank



Thu, 07 Jul 2005 04:16:40 GMT  
 Moving data between registers

Quote:

> I haven't tried it, obviously. Maybe I'll have to.

Well... I was getting segfaults even with the C file cut down to no asm
at all! I *think* the problem was that you allocated some pointers to
float, but didn't allocate anyplace for them to point to(?). (Betov's
right, C really is awful :)  Anyway, I did this:

// gcc -o pawel pawel.c pawel.o

#include <stdio.h>
#include <stdlib.h>

float *floatdiv (float *d, float *s); //asm function declaration

int main(int argc, char *argv[]) {
         float *d;
         float *s;

        float f1;
        float f2;

         int liczba;

        d = &f1;
        s = &f2;

         *d=atof(argv[1]);
         *s=atof(argv[2]);
         liczba =13;

         printf("d = %f\n", *d);
         printf("s = %f\n", *s);

         printf("result = %X\n", *(long int*)floatdiv(d, s));

         return 0;

Quote:
};

It was still seg-faulting when the asm was back in - I think the problem
was that we trashed eax as a pointer, and returned it anyway. I did this:

; nasm -f elf pawel.asm

section .text
global floatdiv
%define d [ebp+8]
%define dHI [ebp+8]
%define dLO [ebp+10]
%define s [ebp+12]

floatdiv:

prolog:
         push ebp
         mov  ebp, esp
         push esi
start:

         mov esi, [ebp+12]    ; float *
        mov eax, [esi]       ; float
         push eax
         pop dx
         pop ax
epilog:
         mov eax, esi  ; return a valid pointer - just to "s"...
         pop esi
         pop ebp
         ret

Now it doesn't seg-fault. I can't say that it's doing anything too
useful. When I replace the "%X" with "%f", I see the number I put on the
command-line, so I guess it's working (i.e. the number we see is the hex
representation of the float). I'm not sure if that's what you intended.
I didn't try to examine ax and dx in any way, but I think they've got
the two parts of the float, alright (briefly). Good luck from there :)

Best,
Frank



Thu, 07 Jul 2005 05:58:30 GMT  
 Moving data between registers

Quote:

> #include <stdio.h>
> #include <stdlib.h>
> float *floatdiv (float *d, float *s); file://asm function declaration
> int main(int argc, char *argv[]) {
>         float *d;
>         float *s;
>         int liczba;
>         *d=atof(argv[1]);
>         *s=atof(argv[2]);
>         liczba =13;

>         printf("d = %f\n", *d);
>         printf("s = %f\n", *s);

>         printf("result = %X\n", *(long int*)floatdiv(d, s));

>         return 0;
> };

I'm a little unclear as to what you are trying to do. Your floatdiv
function is declared as returning a pointer to a float, but in your
C code you cast it to something very different and on top of that
attempt to print out its hex value. 'floatdiv' suggests that you wish
to divide two floats and return the result, another float ??

You have also declared to pointers to floats, but not what they
point to. You should also note that atof requires math.h and
returns a double.

Try this..

#include <stdio.h>
#include <math.h>
float floatdiv (float d, float s);

int main(int argc, char *argv[]) {
         float d, s;

         if(argc < 2) return 0;
         d=(float)atof(argv[1]);
         s=(float)atof(argv[2]);

         printf("d = %f\n", d);
         printf("s = %f\n", s);
         printf("d/s = %f\n", d/s);

         printf("floatdiv result = %f\n", floatdiv(d,s));
         return 0;
 };

- Show quoted text -

Quote:
> And the NASM code is here:

> section .text
> global floatdiv
> %define d [ebp+8]
> %define dHI [ebp+8]
> %define dLO [ebp+10]
> %define s [ebp+12]

> floatdiv:

> prolog:
>         push ebp
>         mov  ebp, esp
>         push esi
> start:

>         mov eax, [ebp+12]
>         push eax
>         pop dx
>         pop ax
> epilog:
>         pop esi
>         pop ebp
>         ret

I'm not familiar wirh Nasm but this function doesn't
appear to do anything much. The arguments, floats,
are each 32-bits, the call is presumeably 32-bits, you
save EBP and ESI before accessing the arguments,
so you're at least 4+4+4 and it that's true you just load
EAX with the first 1st argument and return it, if we exclude
the code..

          push    eax
          pop     dx
          pop     ax

The above code is usually used to return a 32-bit value
(in DX:AX) from a 16-bit call.



Thu, 07 Jul 2005 06:02:55 GMT  
 Moving data between registers

Quote:

> Well, the C code looks as follows:

> #include <stdio.h>
> #include <stdlib.h>
> float *floatdiv (float *d, float *s); //asm function declaration
> int main(int argc, char *argv[]) {
>         float *d;
>         float *s;
>         int liczba;
>         *d=atof(argv[1]);

BANG!

d points nowhere yet, you can't write write anything into where d points
until you make it point somewhere. Easiest fix - don't use pointers here.

Compile using "gcc -Wall" and heed the warnings it gives you.

Phil



Thu, 07 Jul 2005 10:05:29 GMT  
 Moving data between registers
Quote:
> I'm a little unclear as to what you are trying to do. Your floatdiv
> function is declared as returning a pointer to a float, but in your
> C code you cast it to something very different and on top of that
> attempt to print out its hex value. 'floatdiv' suggests that you wish
> to divide two floats and return the result, another float ??

Well actually I'm supposed to write a function to divide two floating point
numbers without using the FPU unit.
The function declaration is given and I can not change it ( I mean I'm not
supposed to), therefore I have to keep the pointers.
The casting: printf("result = %X\n", *(long int*)floatdiv(d, s)); is
necessary to properly display a floating point number in hexadecimal and to
be honest this is another story, anyway it works the way I want it to work
and doesn't cause any trouble....
I don't know any good way to debug NASM functions, therefore what I do when
I want to examine the contents of a particular register is I simply return
it (I move it to EAX and end the program). I know that's obviously not
proffesional, but I don't have too much time to study the usage of gdb or
whatever....
I'm calling a function with two floating point arguments. So the first one
starts at [EBP+8] and it look like this S - sing E - exponent M - mantissa
[EBP+8] [EBP+9] [EBP+10] [EBP+11]

SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM

What I want to do is to

move [EBP+8] & [EBP+9] to DX

so the DX would look like this:

SEEEEEEE EMMMMMMM

0........................................15

therefore the EDX would look like this

SEEEEEEE EMMMMMMM 0000000000000000
0........................................15 16..........................31
in the same fashion I would like to move [EBP+10] & [EBP+11] to AX so AX
would look like this: MMMMMMMM MMMMMMMM
0...................................................15

therefore the EAX would look like this

MMMMMMMM MMMMMMMM 0000000000000000
0...................................................15

16..........................31

Is there any method for this?



Fri, 08 Jul 2005 06:09:32 GMT  
 Moving data between registers

...
 > I don't know any good way to debug NASM functions, therefore what I
 > do when I want to examine the contents of a particular register is I
 > simply return it (I move it to EAX and end the program). I know
 > that's obviously not proffesional, but I don't have too much time to
 > study the usage of gdb or whatever....

Nasm doesn't put out the elf/stabs debug info that gdb likes to see.
However, I've got a weird Perl script that runs Nasm twice (I think) and
puts some debug info into the obj. I've got an "experimental" version of
Nasm that will output some debug info. Either of these make gdb a
*little* friendlier. I've got a ".gdbrc" file that makes gdb act a
little bit like DEBUG (if you think *that's* an improvement :). But if
returning the value works for you, that might be best. I wouldn't say
that gdb was actively unfriendly, but it's a little "reserved", shall we
say :)

 > I'm calling a function with
 > two floating point arguments.

Pointers to floats, right?

 > So the first one starts at [EBP+8] and
 > it look like this S - sing E - exponent M - mantissa [EBP+8] [EBP+9]
 > [EBP+10] [EBP+11]
 >
 > SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
 >
 > What I want to do is to
 >
 > move [EBP+8] & [EBP+9] to DX
 >
 > so the DX would look like this:
 >
 > SEEEEEEE EMMMMMMM
 >
 > 0........................................15
 >
 > therefore the EDX would look like this
 >
 > SEEEEEEE EMMMMMMM 0000000000000000
 > 0........................................15
 > 16..........................31 in the same fashion I would like to
 > move [EBP+10] & [EBP+11] to AX so AX would look like this: MMMMMMMM
 > MMMMMMMM 0...................................................15
 >
 > therefore the EAX would look like this
 >
 > MMMMMMMM MMMMMMMM 0000000000000000
 > 0...................................................15
 >
 > 16..........................31
 >
 > Is there any method for this?

What's at [ebp + 8] and [ebp + 12] *doesn't* look like that, though!
you've gotta "dereference" it first (if I've got the terminology right).

mov esi, [ebp + 8]
mov ax, [esi]      ; I pick on esi, 'cause you saved it...
mov dx, [esi + 2]

Or something similar to that should do what you want - provided that
it's really a single precision float you're pointed at. If atof returns
a double, as Alan indicates, you've got a problem. In the first place,
you'd better allocate "double"s for them to go. If you then called your
function with pointers to them, you might do:

mov esi, [ebp + 8]
fild qword [esi]
fstp dword [esi]
mov ax, [esi]
mov dx, [esi + 2]
; (and don't forget you said you were going to return a pointer!)

... but that would use the FPU, which I understand you're not "supposed"
to do. Or is it just for the divide that you can't use it? I suppose you
could tackle dividing double precision floats without the FPU, too. It'd
be a lot harder, I imagine, but perhaps more useful, too. (and if you're
*really* ambitious, that extended-precision <-> ascii routine is still
on the table, AFAIK)

Anyway, I could be confused about what C's doing to^H^Hfor you, but I
think your problem is that you're trying to "decompose" the address of
the float, not the float itself.

Best,
Frank



Fri, 08 Jul 2005 11:10:47 GMT  
 Moving data between registers

Quote:

> Well actually I'm supposed to write a function to divide two floating point
> numbers without using the FPU unit.

Here is some old code of mine to do that (It was written for Tasm 3.0)

.386p
code32 segment para public use32
       assume  cs:code32, ds:code32, es:code32

REAL4BIAS equ 7Fh
s equ <short>

s_struc struc
        dd  ?  ; ebp
        dd  ?  ; caller
src     dd  ?
dst     dd  ?
s_struc ends
retval = (size s_struc) - 8

ftdiv:
       push    ebp
       mov     ebp, esp
       push    ebx ecx edx esi edi

       mov     edi, [ebp].dst
       mov     esi, [ebp].src
;----------------------------
; signs in bits 1,0 of CL dst,src
;----------------------------
       shl     edi, 1
       rcl     cl, 1
       shl     esi, 1
       rcl     cl, 1
       and     cl, 3
;----------------------------
; check if dst, src are zero
;----------------------------
       mov     eax, 0
       or      esi, esi     ; if src==0, dst/src = 0 !!
       jz      s exit       ; (should be infinity)
       or      edi, edi     ; if dst==0, dst/src = 0 !!
       jz      s exit       ; (should be 1/infinity)
;----------------------------
; get composite bias in CH
;----------------------------
       mov     ch, REAL4BIAS  ; 7Fh

       shld    eax, edi, 8  ; al = dst bias
       shl     edi, 8
       sub     al, REAL4BIAS
       add     ch, al

       shld    eax, esi, 8  ; al = src bias
       shl     esi, 8
       sub     al, REAL4BIAS
       sub     ch, al
;----------------------------
; add explicit '1' to 23-bit significands
;----------------------------
       stc
       rcr     edi, 1
       shr     edi, 8
       stc
       rcr     esi, 1
       shr     esi, 8
;----------------------------
; shift & subtract division
;----------------------------
       mov     dx, 32       ; for 32 bits
       xor     eax, eax     ; result eax == 0
f0a:
       or      edi, edi     ; edi==0 ?
       jz      s f1         ; yes, exit loop
       cmp     edi, esi     ; edi >= esi ?
       jl      s f0b        ; no
       sub     edi, esi     ; edi -= esi
       or      eax, 1       ; eax bit0 = 1
f0b:
       cmp     cx, 1        ; last time ?
       jb      s f0c        ; yes

       shl     eax, 1       ; shl result
       shr     esi, 1       ; shr divisor
f0c:
       dec     dx           ; for 32 bits
       jnz     s f0a        ; continue
;----------------------------
; normalise result
;----------------------------
f1:    test    eax, 80000000h
       jnz     f2
       shl     eax, 1
       jmp     s f1
f2:
       shl     eax, 1       ; remove explicit '1'
;----------------------------
; check magnitude of result
;----------------------------
       mov     edi, [ebp].dst
       shl     edi, 9
       cmp     eax, edi
       jbe     f2
       dec     ch
;----------------------------
; insert biased exponent
;----------------------------
f3:    movzx   edx, ch
       shrd    eax, edx, 8
;----------------------------
; get resultant sign
;----------------------------
       mov     dl, 0        ; assume +result
       cmp     cl, 0        ; +dst / +src ?
       je  s f4           ; yes
       cmp     cl, 3        ; -dst / -src ?
       je  s f4           ; yes
       mov     dl, 1        ; no, -result
f4:
       shr     dl, 1        ;
       rcr     eax, 1       ; insert sign
exit:
       pop     edi esi edx ecx ebx
       pop     ebp
       ret     retval

code32 ends
       end

Quote:
> The function declaration is given and I can not change it ( I mean I'm not
> supposed to), therefore I have to keep the pointers.

Try it without the pointers first and check if it works

Quote:
> The casting: printf("result = %X\n", *(long int*)floatdiv(d, s)); is
> necessary to properly display a floating point number in hexadecimal and to
> be honest this is another story, anyway it works the way I want it to work
> and doesn't cause any trouble....

Ok, I understand

Quote:
> I don't know any good way to debug NASM functions, therefore what I do when
> I want to examine the contents of a particular register is I simply return
> it (I move it to EAX and end the program). I know that's obviously not
> proffesional, but I don't have too much time to study the usage of gdb or
> whatever....

You'll have to talk with someone else about Nasm, I've never used it.


Sat, 09 Jul 2005 07:01:30 GMT  
 
 [ 10 post ] 

 Relevant Pages 

1. moving data between registers

2. Moving data from registers to variables...

3. Moving data between MMX / XMM registers

4. Move integer from XMM to general register

5. moving DD from datasegment to 2 registers?

6. Moving a register to a location

7. Moving a byte in a MMX register

8. NASM (Simple program does not assemble move from register to memory)

9. Error: Clock skew plus hold time of destination register exceeds register-to-register delay

10. Error: Clock skew plus hold time of destination register exceeds register-to-register delay

11. Output registers and data

12. data/register (Fortran/C)

 

 
Powered by phpBB® Forum Software