Author Topic: getting contents of memory address  (Read 16231 times)

nobody

  • Guest
getting contents of memory address
« on: December 06, 2008, 06:02:00 PM »
Hi

I'm obviously missing something here.

I have two C functions (int64val & float64val) that, given an address, are supposed to return the 64-bit contents of that address. The int64val function returns the correct value (printed in hex for consistency) but the float64val does not. I know that 0x40eec30000000000 is the correct answer for the float64val because I did the IEEE math on it to determine the value:

0100000011101110110000110000000000000000000000000000000000000000

0 10000001110 1110110000110000000000000000000000000000000000000000
S      E                             F

S=0
E=1038
E-1023=15
(-1)**S = (-1)**0 = 1
2**(E-127)=2**15=32768
1.F=1.1110110000110000000000000000000000000000000000000000 = 1.922607422
32768*1.922607422=63000

So, why doesn't float64val give me what I need? And, is it possible to write a Nasm function that WILL work?

Compilations, output, and source listings below.

Michael  

=======================================

[michael@localhost Slip]$ gcc -c callint64val.c -o callint64val.o
[michael@localhost Slip]$ gcc -c int64val.c -o int64val.o
[michael@localhost Slip]$ gcc callint64val.o int64val.o -o callint64val
[michael@localhost Slip]$ ./callint64val
0x0000000000000018
0x0000000000000018
[michael@localhost Slip]$ gcc -c callfloat64val.c -o callfloat64val.o
[michael@localhost Slip]$ gcc -c float64val.c -o float64val.o
[michael@localhost Slip]$ gcc callfloat64val.o float64val.o -o callfloat64val
[michael@localhost Slip]$ ./callfloat64val
0x40eec30000000000
0xc1d00f29e0000000
[michael@localhost Slip]$ cat callint64val.c

#include

int main() {
long long int k,m;

k = 24;
    printf("%#018llx\n", k);
    m = int64val(&k);
    printf("%#018llx\n", m);
}

[michael@localhost Slip]$ cat int64val.c

long long int int64val(void *k) {
long long int *m;
m = (long long int *) k;
return *m;
}

[michael@localhost Slip]$ cat callfloat64val.c

#include

int main() {
double a,b;

a = 63.e3;
  printf("%#018llx\n", a);
  b = float64val(&a);
  printf("%#018llx\n", b);
}

[michael@localhost Slip]$ cat float64val.c
double float64val(void *k) {
double *m;
m = (double *) k;
return *m;
}

[michael@localhost Slip]$

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: getting contents of memory address
« Reply #1 on: December 06, 2008, 07:15:40 PM »
Hi Michael,

If, in callfloat64val.c, you prototype float64val as returning double, it magically works!

#include

double float64val (double *);

int main() {
double a,b;

a = 63.e3;
  printf("%#018llx\n", a);
  printf("%f\n", a);
  b = float64val(&a);
  printf("%#018llx\n", b);
  printf("%f\n", b);
}

I figured out from a disassembly that callfloat64val wasn't treating the return from float64val right (like it was returning a single precision float in eax). On a hunch, I tried this, and it worked. Dunno why.

My "asmfloat64val.asm":

global float64val

section .text

float64val:
mov eax, [esp + 4]
fld qword [eax]
ret

also seems to work. This seems to confirm my suspicion that gcc expects a double to be returned on the FPU stack, not in edx:eax like a "long long int". I thought a single precision float would be returned on the FPU stack also, but this may not be true - more experimentation needed!

Best,
Frank

nobody

  • Guest
Re: getting contents of memory address
« Reply #2 on: December 06, 2008, 08:43:43 PM »
Thanks, Frank.

I was hoping not to have to let my main() know what my functions are doing, but may have to rethink that.  Let me know if you come up with something in Nasm that lets me circumvent the prototype. Also, this stuff doesn't have to be portable.

MIchael

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: getting contents of memory address
« Reply #3 on: December 06, 2008, 11:44:51 PM »
Well... you could let main() guess, look to see what gcc made of it, and write a called function to suit. Guessing on both ends hasn't been working out well. :)

A compiler needs to know about "types" and stuff, since it has to make up the instructions. An assembler doesn't need to know, since we're telling it the instructions. But *somebody* has to know!

Easiest way is to bit-bucket the C and write the caller in asm, too. That way, there's no guessing. (if there's an error, it's in the assembly part :)

Many people hold a different opinion.

Best,
Frank

; nasm -f elf asmcallfloat64.asm
; link with previously assembled or compiled .o file
; ld -o asmcallfloat64 asmcallfloat64.o asmfloat64.o
; or ld -o asmcallfloat64 asmcallfloat64.o float64.o

global _start
extern float64val

section .data
    a dq 63.0e3

hnl db "h", 10
    hnl_len equ $ - hnl

word_10 dw 10   ; multiplier for the float-to-ascii routine

section .bss
    numbuf resb 80
    floatbuf resq 1
    bcdbuf rest 1

section .text
_start:
; call our function with "&a"
    push a
    call float64val
    add esp, 4

; result is top of FPU stack - store it
    fst qword [floatbuf]
; print it in hex
    mov eax, [floatbuf + 4]
    call showeaxh
    mov eax, [floatbuf]
    call showeaxh

; print "h" and a newline
    mov ecx, hnl
    mov edx, hnl_len
    call write_stdout

; result is still on top of FPU stack - convert to ascii
    mov edi, numbuf ; buffer for string
    mov ecx, 6 ; number of decimal places
    call ftoa
; print it
    mov ecx, numbuf
; zero-terminated string - we need length
    or edx, byte -1
.getlen:
    cmp byte [ecx + edx + 1], 1
    inc edx
    jnc .getlen
    call write_stdout
; fudge another newline - skip the "h" :)
    mov ecx, hnl + 1
    mov edx, 1
    call write_stdout
; exit
    xor ebx, ebx ;  no error (we claim)
    mov eax, 1 ; __NR_exit
    int 80h
;----------------------    

;-----------------------------------------------------
; ftoa - converts floating point to string
;
; Based on some code "sponged" from a post to clax
; From: "Jim Morrison"
;
; Expects: Number to convert is on stack top - st(0)
;          edi points to buffer to store string
;          ecx = Decimal Places.
;-------------------------------------------------------------

ftoa:
    push eax
    push ecx
    push edx
    push edi
    push esi

mov edx, ecx         ; save a copy of dec places
                         ; if no decimal (integer)
    jcxz .f2a2           ; skip multiply by ten loop
.f2a1:                   ; else loop to "scale" number
    fimul word [word_10]
    loop .f2a1
.f2a2:
    fbstp [bcdbuf]       ; convert to bcd and store
    mov esi, bcdbuf       ; we'll pull digits from there
    mov ecx, 9
.f2a3:
    lodsb                ; get a pair of digits
    mov ah, al           ; move a copy to ah
    shr ah, 4            ; shift out low nibble, keeping high
    and eax, 0F0Fh        ; mask out the digits we want
    add eax, 3030h        ; convert 'em both to ascii
    push eax
    mov al, ah           ; swap and store the other digit
    push eax
    loop .f2a3           ; until done

cmp byte [bcdbuf+9], 0 ; sign flag at bcdbuf + 9 ?
    je .f2a6
    mov al, '-'           ; minus sign if we need it
    stosb                 ; store it at front of our string
.f2a6:

mov ecx, 18
    xor dh, dh
    inc dl
.poploop:
    pop eax
    cmp al, '0'
    jnz .store
    or dh, dh
    jnz .store
    jmp short .nostore
.store:
    stosb
    inc dh
.nostore:
    cmp cl, dl
    jne .nopoint
    or dh, dh       ; if we haven't encountered a non-zero
    jnz .nolz
    mov al, '0'     ; put a zero before the decimal point
    stosb
.nolz:
    mov al, '.'           ; decimal point
    stosb                 ; and store it
    inc dh
.nopoint:
    loop .poploop

mov al, 0
    stosb

pop esi
    pop edi
    pop edx
    pop ecx
    pop eax

ret
;--------------------------------------------------

;---------------------------
write_stdout:
    push ebx
    mov ebx, 1
    mov eax, 4
    int 80h
    pop ebx
    ret
;----------------------------

;------------------------------
showeaxh:
    push eax
    push ebx
    push ecx
    push edx

sub esp, 10h

mov ecx, esp
    xor edx, edx
    mov ebx, eax
.top:
    rol ebx, 4
    mov al, bl
    and al, 0Fh
    cmp al, 0Ah
    sbb al, 69h
    das
    mov [ecx + edx], al
    inc edx
    cmp edx, 8
    jnz .top

mov ebx, 1
    mov eax, 4
    int 80h

add esp, 10h


    pop edx
    pop ecx
    pop ebx
    pop eax
    ret
;------------------------------