Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Jun 23rd, 2005, 12:16 PM   #1
earl
Newbie
 
Join Date: Jun 2005
Posts: 18
Rep Power: 0 earl is on a distinguished road
Access variable within inline asm

Is there a way to access a local variable via inline assembly? I'm working on a Solaris machine with g++. What I'd like to do is this:

long myWrapper(long *value1, long value2)
{
  int tmp;

  asm(" ... "
        "st %l7 tmp"
        " ... ");

  return tmp;
}

So basically I'm going through this assembly algorithm, and the value I want to return from the function is in a particular register in the middle of the algorithm. Any thoughts? Thanks in advance.
earl is offline   Reply With Quote
Old Jun 24th, 2005, 8:03 AM   #2
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
This sort of thing will work:
#include <iostream>

using namespace std;

int yankAsmTooth ();
int main (int argc, char *argv [])
{
    int regVal = yankAsmTooth ();
    cout << regVal;

}
int yankAsmTooth ()
{
    int a;
    __asm
    {
        mov         dword ptr [a],0Ah
    }
    return a;
}
Adapt to your implementation's machine language and your preferred syntax. In my implementation, I could have just put the value in the register used for integer returns and returned, but these things vary. The point is that the machine runs on machine language. Your language must cause that to be emitted, eventually, whether it's compiled, interpreted, or run on a VM of some sort. The machine uses registers. Whatever the language does to move that back and forth across the layer of abstraction, you can also do.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Jun 24th, 2005, 8:55 AM   #3
earl
Newbie
 
Join Date: Jun 2005
Posts: 18
Rep Power: 0 earl is on a distinguished road
Thanks DaWei. This is for SPARC assembly, so the syntax is different and I'm not sure I can reference variable names within inline asm with my compiler.

But I found a similar solution:

register int tmp asm("l2");

asm(" ... "
    "mov %l0, %l2"
    " ... ");

return tmp;

I guess this allocates my local variable to the contents of register %l2, which is a local register for SPARC. I can modify that register in the asm block and the change is made to the variable as well.
earl is offline   Reply With Quote
Old Jun 24th, 2005, 9:22 AM   #4
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
Whatever woiks, see my sig . I judge you'd be interested in exploring the means by which your compiler passes values to, and returns values from, functions. It comes in handy in mixed-language programming. I can't really discern your level of familiarity from the posts thus far; if you'd like some material on a generic (but fairly common), stack-based method, I can probably dig something up.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Jun 25th, 2005, 9:50 AM   #5
earl
Newbie
 
Join Date: Jun 2005
Posts: 18
Rep Power: 0 earl is on a distinguished road
Certainly. I've read a little bit about "function preludes/prologues" with regard to pushing parameters onto the stack, etc. Don't recall much about return values, other than maybe having dedicated registers (i.e., eax on Intel?) for return values...?

But anyways, yeah I'm always interested in building up the bookmark list with some good docs/tutorials for rainy days, if you happen to have anything around... Thanks.
earl is offline   Reply With Quote
Old Jun 25th, 2005, 12:31 PM   #6
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
Nothing so formal. If you've read that, it's probably old news. You'd be surprised, though, how many people don't really understand how parameters are passed or WHY local values disappear when a function returns. Of course, there's nothing in the language standards specifiying that a stack be used, but it's a very common implementation. Some stacks grow downwards, some upwards, some move the pointer before the storage, some after, and some micros don't have a stack at all.

You are correct about the return in the case of the x86 C/C++ platform. Some languages allow multiple returns of any type object, so those are usually stack-based, also. Anyway, here it is, maybe someone can get some insight from it. I hope it reproduces the spacing properly.
GENERIC STACK-USAGE METHOD

Most microprocessors have an internal pointer (the stack pointer) which 
references memory so that the micro can keep track of the point of execution
as it varies because of interrupts, function calls, and so forth.  The stack 
(memory to which it points) is also used by many systems (sometimes 
unfortunately) as a storage place for local values, saved registers, and so 
forth.

Just prior to a call, the stack pointer, which is much like any pointer one 
defines, is pointing to some place in memory (designated by the programmer 
or the operating system) for its use.  When you call a function, it works 
something like this (its usage varies somewhat from language to language -- 
even within one language).

stack pointer -->| orig position | In most systems, the stack pointer moves toward
                 |               | lower addresses as you use it.
                 ~               ~

At call:         | orig position |
                 |   arguments   |
stack pointer -->| last argument |
                 |               |
                 |               |
                 |               |
                 |               |
                 ~               ~

There may be zero or more arguments.  They are pushed onto the stack in a 
predetermined order.  For C/C++, it is right-to-left.  The stack pointer moves 
with each push.

After call:      | orig position |
                 | argument here |
                 | (maybe more)
stack pointer -->| ret addr here |
                 |               |
                 |               |
                 |               |
                 ~               ~

Into procedure   | orig position | 
Arguments avail  | arguments...  | When you modify the argument(s), you modify
for use          | ret addr here | the value(s) stored here.  If an argument
                 |  saved regs,  | is a reference or pointer you may use it to
                 | locals, etc.  | modify the value pointed to elsewhere
                 | in this area  | (in the calling procedure, say).  If you write
stack pointer -->|               | more data to one of the local variables than it
                 ~               ~ can store, guess where the excess winds up.

The function does its work and unwinds the stack (locals, etc.)

Before return    | orig position | Immediately before the return, after storage
                 | arguments...  | for saved registers, locals, etc. has already
stack pointer -->| ret addr here | been recovered (and disappeared). The arguments
                 |               | are still on the stack.
                 |               |
                 |               |
                 ~               ~

After return:    | orig position | Immediately after the return.  The very first
stack pointer -->| arguments...  | thing the machine is going to do next is destroy
                 |               | the arguments, whether you've modified them or not.
                 |               | Sometimes the arguments are removed by the called
                 |               | function and the return address position adjusted
                 |               | appropriately.
                 ~               ~

stack pointer -->| orig position | And it's done; you are right back where you started,
                 |               | bookkeeping wise, when you made the call.  Any 
                 |               | changes you made to the arguments are history, for
                 ~               ~ all practical purposes (they may persist until the
                                   next stack operation).

If you passed an argument as a reference, any modifications you made to the
 value it referred to are, of course, in force.  If you modified the reference, 
itself, to point to something else, you could modify that something else, also 
(for example, subsequent bytes pointed to by a char *).  The reference itself 
disappears.  If you pass an argument by value, that value is perfectly usable 
to the called procedure; it could specify a length to use for some operation, 
for example.  If you modify the value, such modifications disappear when the 
arguments disappear, immediately after the called procedure returns to the 
caller.  If you want lasting changes in the caller, you need to make them by 
reference or RETURN a value from the called procedure.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 8:41 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC