8 Replies - 1662 Views - Last Post: 16 November 2012 - 03:33 PM Rate Topic: -----

#1 carnivroar  Icon User is offline

  • D.I.C Regular

Reputation: 28
  • View blog
  • Posts: 382
  • Joined: 18-September 11

Get value from pointer (assembly subroutine)

Posted 14 November 2012 - 10:34 PM

I have created an external assembly subroutine that returns as output the memory location to the base of an array. The array contains digits of a factorial. For example, 8 factorial, 40320, woudld be:

0....0 <--- return value is the memory location of this
-8...2
-16..3
-24..0
-32..4

Here's the C++ code:

#include <iostream>
using namespace std;

extern "C" long factorial(long);

int main() {
    long* pt = (long*)factorial(4);
    cout << *pt << endl;
    return 0;
}



I know this works because this prints out a correct answer, "4", which comes from 24 (4 factorial). If I put 3, it prints out "6", which again is correct.

But how do I access the other values next to this address?

This post has been edited by carnivroar: 14 November 2012 - 10:35 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Get value from pointer (assembly subroutine)

#2 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1046
  • View blog
  • Posts: 4,449
  • Joined: 09-June 09

Re: Get value from pointer (assembly subroutine)

Posted 14 November 2012 - 10:40 PM

Quote

global factorial

factorial:
   xor    rbx, rbx
   add    rbx, $1
   xor    rdi, rdi
   add    rdi, [esp+4] 
fact:           
   xor    rax, rax
   add    rax, rdi 
   mul    rbx 
   xor    rbx, rbx
   add    rbx, rax 
   dec    rdi 
   cmp    rdi, $1 
   jg     fact  
   xor    rax, rax
   add    rax, rbx 
   ret



But how do I access the other values next to this address?

You should first be sure that the address is valid. You are not allocating any run time memory in your assembly instructions, therefore the pointer to the array that you are returning is is no longer valid once the function ends.

Your simple example that you posted most likely works fine; however, once anything is added to the run time stack after your factorial call, your array contents will most likely get wiped out.

Here is an example illustrating my point, try running the code below and see if it does what you would expect :)

#include <stdio.h>
#include <string.h>

//bad!
int *danger() {
   int temp = 111;
   return &temp;
}

int main() {
   int x;
   int *myInt = danger();

   //copies myInt memory to stdout buffer
   //adds stack frame for printf and wipes out 
   //myInt memory
   printf("*myInt = %d ", *myInt); //prints 111

   printf("*myInt = %d ", *myInt);  // prints garbage


   return 0;
}


This post has been edited by jjl: 14 November 2012 - 10:58 PM

Was This Post Helpful? 0
  • +
  • -

#3 carnivroar  Icon User is offline

  • D.I.C Regular

Reputation: 28
  • View blog
  • Posts: 382
  • Joined: 18-September 11

Re: Get value from pointer (assembly subroutine)

Posted 14 November 2012 - 10:46 PM

[quote name='jjl' date='14 November 2012 - 10:40 PM' timestamp='1352958048' post='1746890']

Quote

You should first be sure that the address is valid. You are not allocating any run time memory in your assembly instructions, therefore the pointer to the array that you are returning is is no longer valid once the function ends.


Oh, it's not that one. That was just a test one. But thanks for digging it up. :)/>

This is the real deal... 10,000 factorial in less than 2 seconds:

global factorial

factorial: 
    push    rbp                   ; save base pointer
    push    1                     ; first number in factorial
    push    -1                    ; flag end of number
    add     rsp, 8                ; move back behind flag
    mov     rbx, 10               ; we'll use this 10 to single out carries
    inc     rdi                   ; increase it by 1 so loop will work
    
f_main_loop:
    cmp     rdi, 1                ; factorial is done computing?
    jle     f_exit                ; done
    dec     rdi                   ; else decrement paramter
    mov     rbp, rsp              ; copy of stack pointer
    xor     rdx, rdx 
    xor     rcx, rcx

f_multiply_loop:
    cmp     qword [rbp], -1       ; check for flag
    jne     f_ml_continue         ; no flag yet, multiply again
    cmp     rcx, 0                ; else check if there's a carry
    je      f_main_loop           ; no carry, back to main loop
    mov     rax, rcx              ; yes carry, need to propagate it

f_ml_propagate_carry:             ; pushes each digit of carry
    xor     rdx, rdx              ; to the next stack location
    div     rbx                   ; gets carry in rax
    mov     [rbp], rdx            ; move remainder to current location
    add     rbp, -8               ; move to the next adress
    cmp     rax,  0               ; is there still a carry?
    jne     f_ml_propagate_carry  ; then do it again
    mov     qword [rbp], -1       ; else push flag back in before leaving
    jmp     f_main_loop 

f_ml_continue:
    mov     rax, [rbp]            ; gets current value in stack address
    mul     rdi                   ; multiply it by factorial (n..1)
    add     rax, rcx              ; carry from previous multiplication
    div     rbx                   ; get only 1 digit
    mov     [rbp], rdx            ; move that digit to current stack address
    mov     rcx, rax              ; rcx holds the current carry
    add     rbp, -8               ; shift go to next stack
    jmp     f_multiply_loop       ; go back to multiply loop

f_exit: 
    mov     rax, rsp              ; STACK POINTER TO RETURN
    add     rsp, 8           
    pop     rbp
    ret



How do I allocate run time memory? Like I said, the correct value is at the first address of the pointer, but I cannot find the rest.

This post has been edited by carnivroar: 14 November 2012 - 10:48 PM

Was This Post Helpful? 0
  • +
  • -

#4 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1046
  • View blog
  • Posts: 4,449
  • Joined: 09-June 09

Re: Get value from pointer (assembly subroutine)

Posted 14 November 2012 - 10:56 PM

Quote

Oh, it's not that one. That was just a test one. But thanks for digging it up


You are still not allocating any run time memory. Take a look at my post again for I have posted an example of what I am trying to illustrate to you.

Quote

How do I allocate run time memory?

http://www.cplusplus...cstdlib/malloc/
Was This Post Helpful? 0
  • +
  • -

#5 carnivroar  Icon User is offline

  • D.I.C Regular

Reputation: 28
  • View blog
  • Posts: 382
  • Joined: 18-September 11

Re: Get value from pointer (assembly subroutine)

Posted 14 November 2012 - 11:24 PM

Okay. I have never used malloc before. Doesn't work... any idea?

#include <iostream>
#include <stdlib.h>
using namespace std;

extern "C" long factorial(long);

int main() {
    malloc(8*sizeof(long));        //10! is 8 digits long
    
    long* pt = (long*)factorial(10);
    
    for (int i = 0; i < 8; i++) {
        cout << (long)*pt << endl; 
        pt+=8;                      //next address?
    }
    
    return 0;
}


This post has been edited by carnivroar: 14 November 2012 - 11:25 PM

Was This Post Helpful? 0
  • +
  • -

#6 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1046
  • View blog
  • Posts: 4,449
  • Joined: 09-June 09

Re: Get value from pointer (assembly subroutine)

Posted 15 November 2012 - 04:52 PM

You need to allocate memory within your factorial assembly function. The memory that you allocate should be the memory that your return from your fuction via poitner.

Here is some information about using malloc in assembly:
http://www.cs.uaf.ed...3_pointers.html

Alternativly, you could allocate the memory on the stack within main and pass the array to your assembly function. Here is a link on passing parameters from C to assembly functions:
http://courses.engr....rog-mixing.html
Was This Post Helpful? 1
  • +
  • -

#7 carnivroar  Icon User is offline

  • D.I.C Regular

Reputation: 28
  • View blog
  • Posts: 382
  • Joined: 18-September 11

Re: Get value from pointer (assembly subroutine)

Posted 15 November 2012 - 11:59 PM

Did it! It works fine except that I get a "Segmentation fault (core dumped)" after around 5000 factorial. Any idea why? The other non-C++ assembly code was giving me 10000 factorial easily.

Also, how do I free the allocated memory? I tried free(pt) (even without doing the pt++) and I got

*** glibc detected *** ./TEST: double free or corruption (out): 0x0000000000a77010 ***
TEST: malloc.c:2451: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted (core dumped)
#include <iostream>
#include <stdlib.h>
using namespace std;

extern "C" long factorial(long);

int main() { 
    long* pt = (long*)factorial(5000);
    while (true) {
        pt++;
        int digit = (int)*pt;
        if (digit == -1) break;
        cout << digit;
    }
    cout << endl;
    return 0;
}



global factorial
extern malloc
 
factorial: 
    push    rdi                   ; save function parameter
    push    8                     ; 8 seems to work 
    call    malloc                ; allocate 8 bytes
    add     rsp, 8                ; restore stack pointer
    pop     rdi                   ; restore function parameter
    push    rbp                   ; save base pointer
    push    rax                   ; save pointer to allocated memory space
    mov     rcx, rsp              ; save stack pointer in rcx
    mov     rsp, rax              ; move rax to stack pointer
    mov     [rax], rcx            ; save stack pointer in the allocated memory space
    mov     qword [rax+8], 1      ; first number in factorial
    mov     qword [rax+16],-1     ; flag end of number
    add     rsp, 8                ; move behind flag
    mov     rbx, 10               ; we'll use this 10 to single out carries
    inc     rdi                   ; increase it by 1 so loop will work
    
f_main_loop:
    cmp     rdi, 1                ; factorial is done computing?
    jle     f_exit                ; done with program
    dec     rdi                   ; else decrement paramter
    mov     rbp, rsp              ; copy of stack pointer
    xor     rdx, rdx 
    xor     rcx, rcx

f_multiply_loop:
    cmp     qword [rbp], -1       ; check for flag
    jne     f_ml_continue         ; no flag yet, multiply again
    cmp     rcx, 0                ; else check if there's a carry
    je      f_main_loop           ; no carry, back to main loop
    mov     rax, rcx              ; yes carry, need to propagate it

f_ml_propagate_carry:             ; pushes each digit of carry
    xor     rdx, rdx              ; to the next stack location
    div     rbx                   ; gets carry in rax
    mov     [rbp], rdx            ; move remainder to current location
    add     rbp, 8               ; move to the next adress
    cmp     rax,  0               ; is there still a carry?
    jne     f_ml_propagate_carry  ; then do it again
    mov     qword [rbp], -1       ; else push flag back in before leaving
    jmp     f_main_loop 

f_ml_continue:
    mov     rax, [rbp]            ; gets current value in stack address
    mul     rdi                   ; multiply it by factorial (n..1)
    add     rax, rcx              ; carry from previous multiplication
    div     rbx                   ; get only 1 digit
    mov     [rbp], rdx            ; move that digit to current stack address
    mov     rcx, rax              ; rcx holds the current carry
    add     rbp, 8                ; shift go to next stack
    jmp     f_multiply_loop       ; go back to multiply loop

f_exit: 
    add     rsp, -8           
    pop     rsp
    pop     rax
    pop     rbp
    ret


This post has been edited by carnivroar: 16 November 2012 - 12:17 AM

Was This Post Helpful? 0
  • +
  • -

#8 carnivroar  Icon User is offline

  • D.I.C Regular

Reputation: 28
  • View blog
  • Posts: 382
  • Joined: 18-September 11

Re: Get value from pointer (assembly subroutine)

Posted 16 November 2012 - 02:23 AM

View Postjjl, on 15 November 2012 - 04:52 PM, said:

Alternativly, you could allocate the memory on the stack within main and pass the array to your assembly function. Here is a link on passing parameters from C to assembly functions:
http://courses.engr....rog-mixing.html

Oh, great. I did this instead and it worked. :)

Thank you sooooo much

Here's what I was able to compute

http://rcs.hostoi.co...0factorial.html
Was This Post Helpful? 0
  • +
  • -

#9 jjl  Icon User is offline

  • Engineer
  • member icon

Reputation: 1046
  • View blog
  • Posts: 4,449
  • Joined: 09-June 09

Re: Get value from pointer (assembly subroutine)

Posted 16 November 2012 - 03:33 PM

No problem :)/> I ended up writing blog entry about returning pointers to temporary stack memory. If you care to see a more in depth explanation on why your first implementation did not work as expected.

http://www.dreaminco...y-stack-memory/

This post has been edited by jjl: 16 November 2012 - 03:34 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1