views:

1077

answers:

4

I need to create an assembly function that adds two positive numbers together, called by a C program.

The C program would look like this:

#include <stdio.h>

int main(void){
int a = 0;
int b = 0;
int c = 0;
printf( "Enter first number: " );
scanf( "%d", &a );
printf( "Enter second number: " );
scanf( "%d", &b );
sum();
printf( "Answer is %d\n", sum );
}

A requirement is that the assembly function (sum()) should not have any parameter passing nor return any value. Also, the assembly function is located in a separate file, sum.s, if that matters.

I tried a lot, and read a lot. Still, I can't access the variables inside main(). Thank you for your help. :)

+2  A: 

When you invoke sum(), the compiler will push (onto the stack) the address of the current instruction pointer, and then jump to the location of the subroutine. Pushing the current intruction pointer is so that the subroutine can return by popping the address.

So, inside the subroutine, the first thing on (i.e. at the bottom of, since the stack pushes from top to bottom) is the return address. Immediately above that on the stack are the local variables of the routine which called the subroutine.

So, if esp is the stack pointer register, and [esp] is the location in memory which sp is pointing to, and assuming 32-bit code, the sum subroutine should find that addresses like [esp+4], [esp+8], and [esp+12] contain the addresses of the local variables.

To confirm what I've said, I suggest that you look at the assembly emitted by your C code: either by using a debugger to disassemble the machine code, or by using a compiler command-line option to generate an assembly-language listing file.


Edit: moonshadow is right about this being a 'brittle' solution. For example, whether or the 'c' variable is stored on the stack or instead stored in a register (or whether it's even defined at all, instead of the compiler's assuming that it's a hard-coded constant zero) may vary depending on whether compiler optimizations are enabled.

ChrisW
Except that the compiler can optimize a, b, and c away (or into registers or whatever) and they do not really "exist". Maybe Student could declare them ``volatile``.
pmg
@pmg: actually, it can't - the addresses of a and b are taken for the scanf() calls, and the address of c will be taken for printf()'s varargs array when that line is fixed, so the compiler will be forced to read/write that data from actual memory locations.
moonshadow
Yes, volatile *might* be good, and/or compile without compiler optimizations enabled.
ChrisW
"the address of c will be taken for printf()'s varargs array" -- Really? I would have thought that's the value of c (not the address of c) that's being pushed there as a parameter to the printf function.
ChrisW
@Chris: well, that's what happens on *my* platform. Perhaps reading the ABI docs is an even better idea than I first thought ;)
moonshadow
You're better off using the frame pointer rather than the stack pointer - it explicitly points to the stack frame. `[%ebp]` will give you the saved frame pointer, which is the address of the caller's stack frame. So (negative) offsets from this value will be the caller's local variables - that's how debuggers generally work.
caf
+2  A: 

No parameter passing seems a bit of an odd requirement - it's likely to result in quite brittle code; normally you'd get the C code to pass in parameters as normal and the assembly function would pull them from the appropriate registers and/or the stack as defined by the calling convention, and write the result there.

Still, if that is really what you want, it's feasible. What you'll need to do is read your compiler's ABI documentation to work out how it lays out its stack frame. Then your assembly function will need to work out where the caller's stack frame is - a pointer or offset to it, along with the return address and any parameters, is generally pushed on the stack when any function is called - and hence where the local variables a, b and c are in memory. The layout will depend on the ABI, and as you read those docs you'll discover it also depends on the calling convention and what you've locally declared in scope in the caller; and possibly optimisation level. So your resulting assembly function will be very tightly bound to your current implementation - brittle - and will likely break if pretty much anything changes. A general solution is not possible.

Incidentally, in your printf( "Answer is %d\n", sum ); line, I think you mean c, not sum. sum would yield the address of the sum() function, which will likely get hardwired in by the compiler and fixed at link time, so there is no way to make that symbol print the runtime result.

moonshadow
+1  A: 

I suggest making assumptions on how the stack is built. This is the way I picture it:

Before the function call:

-------
|  a  |
-------
|  b  |
-------
|  c  |
-------

After the function call:

------- TOS
|  a  |
------- TOS - 4
|  b  |
------- TOS - 8
|  c  |
------- TOS - 12
| ret |
| eip | 
------- TOS - 16

and you have:

ESP = TOS - 16

Now:

mov eax, ss:[esp + 12] ; eax = a
add eax, ss:[esp +  8] ; eax += b
mov ss:[esp +  4], eax ; c   = eax
ret

Should do the trick

Nathan Fellman
+2  A: 

So far the answers here talk about some very complex and compiler specific solutions (actually they're also dependent on what options might be used to perform the compile).

I wonder if for this assignment all that's being looked for is to use global variables to pass the parameters and the result?

Relying on the layout of the local variables in another function and their relationship to the return address location is rather... crazy.

Michael Burr
I was assuming that when the querent said "The C program would look like this", they meant "exactly like this". If not then yeah, anything goes.
moonshadow
Yes it woud be a very different answer if the question used global variables instead of local variable.
ChrisW
@moonshadow - yes, you're right. I guess that I read some questions an think that they're presenting an approach rather than saying "here are the constraints". If this question is based on homework, I'd hope that the instructor is not looking for a solution based on how locals *might* be laid out by a compiler. If this question is a 'programming puzzle', then my answer is off-base.
Michael Burr