Author Topic: Mixed assembly and C  (Read 13992 times)

Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Mixed assembly and C
« on: January 18, 2010, 06:04:18 AM »
How do i call the function and acess the struct values returned from it?
Example:

Code: [Select]
struct foo {
        int a;
        int b;
        int c;
        int d;
};

struct foo
bar (void)
{
        struct foo ret;
        ret.a = 1;
        ret.b = 2;
        ret.c = 3;
        ret.d = 4;
        return ret;
}

Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Re: Mixed assembly and C
« Reply #1 on: January 18, 2010, 06:07:24 AM »
Plus...
mov dword & var,register
Wtf it does?
[dword &,han?]

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2437
  • Country: us
Re: Mixed assembly and C
« Reply #2 on: January 24, 2010, 08:25:27 PM »
I'm highly inexpert at C, but...

Code: [Select]
struct foo
bar (void)
{
     struct foo ret;
     ret.a = 1;
     ret.b = 2;
     ret.c = 3;
     ret.d = 4;
     return ret;
}

... if I understand this correctly, you're returning the address of a local (stack... "automatic") variable. I don't think that's gonna work.

"mov dword & var, reg" is secret undocumented Nasm syntax. It means the same as "mov [var], reg". You're not supposed to know about it! :) Where'd you see that?

I think we can help you with accessing structure elements C<->asm, but explain more what you're trying to do... Where does an "instance" of this structure exist - hopefully not as an "automatic" variable which is going to go away when the function exits...

Best,
Frank


Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Re: Mixed assembly and C
« Reply #3 on: January 25, 2010, 04:54:26 AM »
Hello frank! ^^
Dude...even when the variable I return is at a global scope,I still get a segfault.
Take a look:
teste.c:
Code: [Select]
struct st {
    int a;
    int b;
};

struct st h;

struct st teste() {
    h.a = 10;
    h.b = 30;
    return h;
}
teste2.asm:
Code: [Select]
extern teste

section .text
global main
main:
call teste

mov eax,1
mov ebx,0
int 80h

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Mixed assembly and C
« Reply #4 on: January 25, 2010, 05:49:24 AM »
Dude...even when the variable I return is at a global scope,I still get a segfault.

I could not duplicate the segfault issue with your example on my box.

Please post your platform (Windows, Linux, etc...), version of NASM, and the assemble/compile/link commands you are using to build your example.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2437
  • Country: us
Re: Mixed assembly and C
« Reply #5 on: January 25, 2010, 08:48:27 AM »
Heh, well if he's running 'doze, the int 80h might be a problem. :)

I can confirm that it segfaults (nasm -f elf teste2.asm / gcc -o teste teste.c teste2.o)

Seems to be happening at the "h.a = 10" - mov [ecx], eax, with eax 10 (if I change the  file to "h.a = 20", eax is 20). ecx is 0x4004829B - the range that "mmap" uses. I would expect a "static" variable to be around 0x0804???? - I added "static" - no help.

Looks like a C problem to me! :)

Seriously, your asm looks fine (assuming Linux!), and it isn't crashing there... or trying to return from there... I don't know what the problem could be!

Best,
Frank


Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Re: Mixed assembly and C
« Reply #6 on: January 25, 2010, 09:32:12 AM »
I'm running in Debian 5.0.
Nasm version: 2.07
GCC version: 4.3.2
ld version: the one wich comes with binutils 2.18
The commands I used were very similar to Frank's.
----
Quote
'doze
Han?
---
Hum...very strange!
Keith,wich compiler and etc did you use?
How do I make something like this work? o-o

Thanks for your help people!

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2437
  • Country: us
Re: Mixed assembly and C
« Reply #7 on: January 25, 2010, 09:39:56 AM »
Make that 0x0804xxxx - smiley bit me!

Hey! You never told me where you saw "mov &var, reg"! It'll work, it just isn't well known.

I tried this modification of your C file:

Code: [Select]
struct st {
    int a;
    int b;
};

struct st h;

struct st teste() {
    printf("h=%x ; &h=%x\n", h, &h);
    h.a = 20;
    h.b = 30;
    return h;
}

Says 0... both times. 'Splains the segfault, but not the solution. I think you need a C guru, son. :)

Best
Frank



Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Re: Mixed assembly and C
« Reply #8 on: January 25, 2010, 09:46:28 AM »
Ha,I saw the "mov &" thing on a tutorial explaining how to interact the X11 librarie with assembly.
WOW...it looks like i'll never find the solution...t-t
Thanks dude...
Ha...I also tried to assemble with the gnu assembler and got the same result.

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Mixed assembly and C
« Reply #9 on: January 25, 2010, 04:16:49 PM »
Keith,wich compiler and etc did you use?

My main box is a Mac running OS 10.6 (Snow Leopard):

NASM 2.07 from Source: nasm -fmacho -o main.o main.asm
gcc 4.2.1 from XCode: gcc -m32 -c -o struct.o struct.c
ld from XCode: ld -o main.bin main.o struct.o

main.bin runs without any segfaults.

I can try again tonight on Ubuntu/ELF and see what happens.

Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Re: Mixed assembly and C
« Reply #10 on: January 25, 2010, 04:34:45 PM »
Hum...try then...o-o
And why the f*** this works in a Mac box?

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Mixed assembly and C
« Reply #11 on: January 25, 2010, 07:38:26 PM »
Use pointer parameters and dereference the argument. The following example increments the x, y, and z values in a POINTS structure.

main.c
Code: [Select]
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
int x, y, z;
} POINTS;

void IncrementPoints( POINTS * ptrPoints ) __attribute__((stdcall));

int main ( void )
{
POINTS * here;
here = (POINTS *) malloc( sizeof( POINTS ) );
here->x = 1;
here->y = 2;
here->z = 3;
fprintf( stdout, "x: %ld\ny: %ld\nz: %ld\n",
                here->x, here->y, here->z );
IncrementPoints( here );
fprintf( stdout, "x: %ld\ny: %ld\nz: %ld\n",
here->x, here->y, here->z );
free( here );
return( 0 );
}

incpts.asm
Code: [Select]
BITS 32

STRUC POINTS
.x RESD 1
.y RESD 1
.z RESD 1
ENDSTRUC


SECTION .text

Global IncrementPoints
IncrementPoints:
STRUC IP_ARGS
.ptrPoints RESD 1
ENDSTRUC
Push Ebp
Mov Ebp, Esp
Push Esi
Mov Esi, [Ebp + 8 + IP_ARGS.ptrPoints]
Inc DWORD [Esi + POINTS.x]
Inc DWORD [Esi + POINTS.y]
Inc DWORD [Esi + POINTS.z]
Xor Eax, Eax
Pop Esi
Leave
Ret

Build and Run with:
Code: [Select]
nasm -f elf incpts.asm -o incpts.o
gcc -o test main.c incpts.o
./test

A few things to note are; a) I use stdcall convention whenever I write assembly, so you'll notice the __attribute__ declaration to ensure that it uses stdcall, if you use a different convention then you will need to change that. b) I decided to allocate the 'here' structure on the heap, if you want to use a local stack based variable (ie POINTS here) just call the procedure using 'IncrementPoints( &heap);' instead and all should work fine.

Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Mixed assembly and C
« Reply #12 on: January 25, 2010, 08:04:09 PM »
Sorry about that, the answer is the same as before (use pointers) but the demo code was reversed...

main.asm
Code: [Select]
BITS 32

STRUC POINTS
.x RESD 1
.y RESD 1
.z RESD 1
ENDSTRUC

Extern initPoints
Extern printPoints
Extern freePoints

SECTION .bss
ptrPoints RESD 1

SECTION .text
Global main
main: Push Ebp
Mov Ebp, Esp

Call initPoints
Mov [ptrPoints], Eax
Push Eax
Call printPoints
Mov Eax, [ptrPoints]
Mov DWORD [Eax + POINTS.x], 12
Push DWORD [ptrPoints]
Call printPoints
Push DWORD [ptrPoints]
Call freePoints

Leave
Ret

myPoints.c
Code: [Select]
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
int x, y, z;
} POINTS;

POINTS * initPoints( void );
void printPoints( POINTS * ptrPoints );
void freePoints ( POINTS * ptrPoints );

POINTS * initPoints( void )
{
POINTS * tmp = (POINTS *) malloc( sizeof( POINTS ) );
tmp->x = tmp->y = tmp->z = 1;
return tmp;
}

void printPoints( POINTS * ptrPoints)
{
fprintf( stdout, "x:\t%d\ny:\t%d\nz:\t%d\n",
ptrPoints->x, ptrPoints->y, ptrPoints->z );
}

void freePoints( POINTS * ptrPoints )
{
free( ptrPoints );
}

Build and Run with:
Code: [Select]
gcc -c -o myPoints.o myPoints.c
nasm -f elf main.asm -o main.o
gcc -o test main.o myPoints.o
./test

Sorry about that, I'm not in the best frame of mind atm.  :-\

Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me

Offline dbfn

  • Jr. Member
  • *
  • Posts: 17
Re: Mixed assembly and C
« Reply #13 on: January 25, 2010, 08:47:01 PM »
Yeap,returning pointers I had no problems since the begining.
But what about returning the struct? : x

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Mixed assembly and C
« Reply #14 on: January 26, 2010, 12:12:01 AM »
Yeap,returning pointers I had no problems since the begining.
But what about returning the struct? : x

Well, from a low level viewpoint, you can't really return a "struct", you can only return a pointer/address to it *or* return its contents if it is small enough to fit into 32 bits (in your case).

Utilizing structs in assembly language, just as in C, requires the knowledge of the size and contents of a structure. C makes it easier to deal with conceptually, but the fact is that structs are just arrays with potentially different sized/typed/named elements, so you have to treat them as such.

What you can do, is ensure that the definition of a particular structure is defined in both the C and ASM code (see Bryant's first example with the POINTS struct), and then utilize the language constructs of each to intuitively address/access the members of said structure.