NASM - The Netwide Assembler

NASM Forum => Using NASM => Topic started by: dbfn on January 18, 2010, 06:04:18 AM

Title: Mixed assembly and C
Post by: dbfn 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;
}
Title: Re: Mixed assembly and C
Post by: dbfn on January 18, 2010, 06:07:24 AM
Plus...
mov dword & var,register
Wtf it does?
[dword &,han?]
Title: Re: Mixed assembly and C
Post by: Frank Kotler 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

Title: Re: Mixed assembly and C
Post by: dbfn 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
Title: Re: Mixed assembly and C
Post by: Keith Kanios 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.
Title: Re: Mixed assembly and C
Post by: Frank Kotler 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

Title: Re: Mixed assembly and C
Post by: dbfn 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!
Title: Re: Mixed assembly and C
Post by: Frank Kotler 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


Title: Re: Mixed assembly and C
Post by: dbfn 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.
Title: Re: Mixed assembly and C
Post by: Keith Kanios 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.
Title: Re: Mixed assembly and C
Post by: dbfn on January 25, 2010, 04:34:45 PM
Hum...try then...o-o
And why the f*** this works in a Mac box?
Title: Re: Mixed assembly and C
Post by: Bryant Keller 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
Title: Re: Mixed assembly and C
Post by: Bryant Keller 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
Title: Re: Mixed assembly and C
Post by: dbfn 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
Title: Re: Mixed assembly and C
Post by: Keith Kanios 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.
Title: Re: Mixed assembly and C
Post by: dbfn on January 26, 2010, 01:17:00 AM
all right then....
Title: Re: Mixed assembly and C
Post by: Frank Kotler on January 26, 2010, 03:08:40 AM
Well, I still don't understand why your example ran on Keith's Mac! (OMG, they really *are* better! :)

I sympathize with your problems with structures in C. When I was trying to teach myself C, I utilized structures extensively. Had *no* idea what I was doing, just bashed at it until it worked - which it eventually did. Now that I've learned assembly, I understand why "returning the structure" wasn't working. The return value is a... well, 16-bit then, 32-bit or more now, value - "the structure" ain't going to fit.

Thanks to Bryant for the example!

Best,
Frank

Title: Re: Mixed assembly and C
Post by: Keith Kanios on January 26, 2010, 06:30:17 AM
Hum...try then...o-o

Segfaulted on 32-bit Ubuntu. I checked a dump of the file and the Ubuntu version is still trying to access the stack, where-as the Mac version is not.

Ubuntu Binary Dump:
Code: [Select]
; Disassembly of file: main.bin
; Mon Jan 25 23:37:56 2010
; Mode: 32 bits
; Syntax: YASM/NASM
; Instruction set: 80386
 
 
global _edata
global __bss_start
global _end
global teste
global _start
global h
 
 
SECTION .text   align=16 execute                        ; section number 1, code
 
teste:  ; Function begin
        push    ebp                                     ; 080480A0 _ 55
        mov     ebp, esp                                ; 080480A1 _ 89. E5
        mov     ecx, dword [ebp+8H]                     ; 080480A3 _ 8B. 4D, 08
        mov     dword [h], 10                           ; 080480A6 _ C7. 05, 080490E8(d), 0000000A
        mov     dword [?_001], 30                       ; 080480B0 _ C7. 05, 080490EC(d), 0000001E
        mov     eax, dword [h]                          ; 080480BA _ A1, 080490E8(d)
        mov     edx, dword [?_001]                      ; 080480BF _ 8B. 15, 080490EC(d)
        mov     dword [ecx], eax                        ; 080480C5 _ 89. 01
        mov     dword [ecx+4H], edx                     ; 080480C7 _ 89. 51, 04
        mov     eax, ecx                                ; 080480CA _ 89. C8
        pop     ebp                                     ; 080480CC _ 5D
        ret     4                                       ; 080480CD _ C2, 0004
; teste End of function
 
_start: ; Function begin
        call    teste                                   ; 080480D0 _ E8, FFFFFFCB
        mov     esi, h                                  ; 080480D5 _ BE, 080490E8(d)
        mov     eax, 1                                  ; 080480DA _ B8, 00000001
        mov     ebx, 0                                  ; 080480DF _ BB, 00000000
; Note: Function does not end with ret or jmp
        int     -128                                    ; 080480E4 _ CD, 80
; _start End of function
 
 
SECTION .bss    align=4 noexecute                       ; section number 2, bss
 
h:                                                      ; qword
        resb    4                                       ; 080490E8
 
?_001:                                                  ; dword
        resd    1                                       ; 080490EC

I'm not exactly an expert in C or compiler theory, and perhaps I am missing something, but I find that trying to access an unknown portion of the stack seems rather foolish... especially when it is above any known portion of a downward growing stack (ebp+[0-3] = ebp; ebp+[4-7] = return address; ebp+[8+] = ???).

Perhaps there was a faulty assumption by the compiler that a pointer to the structure was going to be supplied as the first/only argument?

Perhaps mov ecx, dword [ebp+8H] is consistently grabbing an invalid or NULL pointer, causing a segfault on the subsequent mov dword [ecx], eax?


Mac Binary Dump:
Code: [Select]
; Disassembly of file: main.bin
; Mon Jan 25 23:23:53 2010
; Mode: 32 bits
; Syntax: YASM/NASM
; Instruction set: 80386


global __mh_execute_header
global start
global _teste
global _h

__mh_execute_header equ 00001000H                       ; 4096


SECTION ._TEXT.__text align=1 execute                   ; section number 1, code

start:  ; Function begin
        call    _teste                                  ; 1FB7 _ E8, 0000000C
        mov     eax, 1                                  ; 1FBC _ B8, 00000001
        mov     ebx, 0                                  ; 1FC1 _ BB, 00000000
        int     -128                                    ; 1FC6 _ CD, 80

_teste:
        push    ebp                                     ; 1FC8 _ 55
        mov     ebp, esp                                ; 1FC9 _ 89. E5
        sub     esp, 8                                  ; 1FCB _ 83. EC, 08
        call    ?_001                                   ; 1FCE _ E8, 00000000
?_001:  pop     ecx                                     ; 1FD3 _ 59
        lea     eax, [ecx+102DH]                        ; 1FD4 _ 8D. 81, 0000102D
        mov     eax, dword [eax]                        ; 1FDA _ 8B. 00
        mov     dword [eax], 10                         ; 1FDC _ C7. 00, 0000000A
        lea     eax, [ecx+102DH]                        ; 1FE2 _ 8D. 81, 0000102D
        mov     eax, dword [eax]                        ; 1FE8 _ 8B. 00
        mov     dword [eax+4H], 30                      ; 1FEA _ C7. 40, 04, 0000001E
        lea     eax, [ecx+102DH]                        ; 1FF1 _ 8D. 81, 0000102D
        mov     eax, dword [eax]                        ; 1FF7 _ 8B. 00
        mov     edx, dword [eax+4H]                     ; 1FF9 _ 8B. 50, 04
        mov     eax, dword [eax]                        ; 1FFC _ 8B. 00
        leave                                           ; 1FFE _ C9
        ret                                             ; 1FFF _ C3
; start End of function


SECTION ._DATA.__common align=4 noexecute               ; section number 2, bss

_h:                                                     ; byte
        resb    8                                       ; 2000


SECTION ._IMPORT.__pointers align=4 noexecute           ; section number 3, data

        db 00H, 20H, 00H, 00H                           ; 3000 _ . ..

The above Mac version, although more indirect, is a little "smarter" (probably has more to do with ABI/API design) in that it only tries to return the values of each structure member in eax and edx. This is the only major difference between the two systems/binaries and could definitely account for a segfault.

In the end, however, you did something that was theoretically acceptable to the compiler but the real results were obviously nothing that was intended. I would recommend brushing up on Pointers in C/C++ (http://www.cplusplus.com/doc/tutorial/pointers/).

Another note about what you are trying to achieve. If you want direct access to the C struct in ASM, you would most likely want to put an extern for it in the ASM code and address it directly.

Title: Re: Mixed assembly and C
Post by: Frank Kotler on January 26, 2010, 07:35:04 AM
That is truely bizzarre. And some fancy footwork on the part of the Mac!

I have a question about mixed C and asm. What's the C for? :)

Best,
Frank

Title: Re: Mixed assembly and C
Post by: Bryant Keller on January 26, 2010, 04:39:01 PM
dbfn,

You could _technically_ return a struct even if it doesn't fit into Eax, although I've never seen it done in C. The technique accessed the previous frame to modify a previously declared structure at a known point on the frame. I don't exactly remember where I saw this (I do remember it was written in GoASM's USEDATA directive) but for the sake of modularity it would be worthless -- it has to know where the variable is in the previous frame.

Personally, I prefer to use the dereferenced pointer method shown in my previous post because it could easily be extended to void pointer types to allow for structures which share a base structure (think along the lines of inheritance, very useful in IP based protocols where different "payloads" decide the rest of the structure even though the "header" is effectively the same).

Just to be consistant I would avoid the use of returned structures, yes there are some compilers which will detect a structures size and put it in a "known" location like FPU registers or adjust the stack by moving the ebp/eip to make room for the value. But to be honest there is no "universal method" used by any compiler and your code will be restricted to only a specific set of build tools, whereas the pointer method is always going to be in Eax.

Quote
Thanks to Bryant for the example!

Frank,

No problem man. Actually, for the sake of this new forum I've decided to start saving a local copy of my responses as well as working examples in a neat directory structure.

Code: [Select]
/home/bkeller/Desktop/Support/[username]/[subject]/
/home/bkeller/Desktop/Support/[username]/[subject]/src/*.*
/home/bkeller/Desktop/Support/[username]/[subject]/responses/###.txt

This way not only do I know for certain that all code I post will work (no more tongue-and-cheek code) but I'll also have a way to quickly look up past responses in the event I have a repeat question. I hope this will make me more effect in responding to any questions.

We've talked before about me joining sourceforge to take part in on the discussion group but as I mentioned before, I hated the sourceforge based forums due to their poor support for displaying code snippets. (You would think a site dedicated to hosting open source projects would at least allow users to post readable code). I honestly can't express how happy I am that the board is now running SMF and I look forward to being a regular member here. :)

Keith,

Mac's are so cute. The Mac dump you posted has me completely boggled as to why in the world it would want to use position relative addressing for accessing memory locations. That code reminds me of the old K32B.INC include Homer and I created for tiny executables on win32 (no imports) through use of PRA (The Delta Method) and a few PEB hacks. Outside of that include I've actually never seen PRAs used for, well anything (except maybe shellcode and viral type code). lol

If you have any other code dumps like that (being as I don't own a Mac) toss them to me in PM, I'd love to see what other little tricks Mac compilers have picked up. :)

Regards,
Bryant Keller