Author Topic: Nasm and C??  (Read 16297 times)

Offline MJaoune

  • Jr. Member
  • *
  • Posts: 94
Nasm and C??
« on: May 25, 2011, 03:33:15 PM »
How to call C functions from an ASM project?? I searched the whole forum and didn't find anything handy  :-\, so please post a good full help that everybody can read this topic.

Thanks

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2382
  • Country: us
Re: Nasm and C??
« Reply #1 on: May 25, 2011, 06:30:13 PM »
Well, the Friendly Manual has a pretty good run-down on it:

http://www.nasm.us/xdoc/2.09.08/html/nasmdoc9.html#section-9.1

"global" and "extern" are the keys to it. A symbol - function or variable - which exists in your file, that you wish to make known to the outside world, is "global". A symbol - function or variable - which is used in your code, but exists someplace else, is "extern". (some assemblers use "public" and "extrn") This applies to languages other than C, BTW - I think I have an example of an asm function that can be called from Fortran!

There's the question of "how do we spell it". Almost everybody besides ELF spells it "_main" and "_printf". ELF spells it "main" and "printf". OpenWatcom C spells it "main_" and "prinf_"! Lord knows what C++ is going to do with it - declare your asm function as 'extern "C" myfunc', I think.  The section(s) in the Friendly Manual mentions that you may wish to use a macro to do this conversion. Better yet (IMO) is to write it as "main" and "printf", and use the "--prefix _ " and/or "--postfix _" command line options to put the underscores where your compiler expects. Strictly speaking, I think this is a "linker requirement" - the compiler has to put the underscores the same places we do, but it amounts to the same thing...

Push the parameters (right to left, for C), and "call _foof" ("_foof" being my idea of how C would spell "foo" :) ). That's about it...

A couple of "clues"... "printf" always expects floats to be double precision (8 bytes, 64 bits), and "printf" doesn't print anything until the buffer is flushed.

What part(s) are you having trouble with?

Best,
Frank


Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Nasm and C??
« Reply #2 on: May 25, 2011, 06:35:41 PM »
Push the parameters (right to left, for C), and "call _foof" ("_foof" being my idea of how C would spell "foo" :) ). That's about it...

... for 32-bit/CDECL*

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2382
  • Country: us
Re: Nasm and C??
« Reply #3 on: May 25, 2011, 06:49:30 PM »
Good point! All of the above applies to 32-bit code. The Fine Manual has sections on interfacing with 64-bit C(s) - different for Unix and Windows. Links to the abi(s) and everything. (the careful observer will note that, if you delve "under the hood", C ain't quite as "standardized" and "portable" as it says on the tin) We can cope! :)

Best,
Frank


Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: Nasm and C??
« Reply #4 on: May 25, 2011, 08:21:44 PM »
example for 32 bit linux
Code: [Select]
EXTERN gnu_get_libc_version
EXTERN gnu_get_libc_release
EXTERN printf

;for 32bit linux
;build
;nasm -f elf -g ctest.asm
;gcc ctest.o -o test


; macro for calling C functions from assembly language programs.
; pushes the arguments on the stack, makes the function call and
; then cleans up the stack. follows the cdecl calling convention
%macro ccall 1-*
        %define __procedure_call %1

        %rep %0-1
                %rotate -1
                push %1
        %endrep

        call __procedure_call

        %if (%0-1)
                add esp, (%0-1)*4
        %endif

%endmacro

EXIT_SUCCESS equ 0
NULL equ 0


SECTION .data

        fmtstr db "You are currently using glibc version %s %s", 10, 0
        version dd NULL         ;will contain pointer to a version string
        release dd NULL         ;will contain pointer to a release string

SECTION .text
GLOBAL main

main:

        ccall gnu_get_libc_version
        mov [version], eax
        ccall gnu_get_libc_release
        mov [release], eax

        ccall printf, fmtstr, dword[version], dword[release]

        mov eax, EXIT_SUCCESS
        ret

i've spent the last couple of months creating macros and include files for system programming with 32-bit linux, i'm so far from finished its not even funny :D
« Last Edit: May 25, 2011, 08:26:23 PM by brethren »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2382
  • Country: us
Re: Nasm and C??
« Reply #5 on: May 25, 2011, 09:58:05 PM »
Good one, Brethren! (How old is "2.3.6 stable"? :) )

Where'd you learn of the existance of these functions? I can't find 'em anywhere in the man pages!

The most extensive include files for Linux (and BSD and BeOS) I've seen are in the "asmutils" package.

Best,
Frank


Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: Nasm and C??
« Reply #6 on: May 25, 2011, 10:33:41 PM »
i'm reading a great book called the linux programming interface
http://www.amazon.com/Linux-Programming-Interface-System-Handbook/dp/1593272200

its a massive book and its geared toward C programmers but i'm having a lot of fun discovering stuff i had no idea existed :)

btw i've seen the asmutils package and its a great resource but i want a set of inc files that are functionally reasonably similar to the C header files to be useful.
This is an example of what i mean, stdio.inc (its not yet finished)
Code: [Select]
%ifndef __STDIO_INC__
%define __STDIO_INC__

; end-of-file character
EOF equ -1

%ifndef __NULL_defined__
%define __NULL_defined__
NULL equ 0              ;also defined in stdlib.inc, string.inc, unistd.inc
%endif

; values from /usr/include/bits/stdio_lim.h
L_tmpnam        equ 20          ;how long an array of bytes needs to be for tmpnam
TMP_MAX         equ 238328      ;the minimum number of unique filenames generated by tmpnam
FILENAME_MAX    equ 4096        ;maximum length of a filename
L_ctermid       equ 9           ;how long an array of bytes to be passed to ctermid
L_cuserid       equ 9           ;how long an array of bytes to be passed to cuserid

FOPEN_MAX       equ 16          ;max number of files that can be open at once
IOV_MAX         equ 1024

%defstr P_tmpdir "/tmp"         ;default path prefix for tmpnam and tempnam

; possibilities for third argument to fseek
; these value are also defined in unistd.inc
%ifndef __UNISTD_INC__
SEEK_SET equ 0
SEEK_CUR equ 1
SEEK_END equ 2
%endif

; stdio.h defines BUFSIZ as BUFSIZ=_IO_BUFSIZ, in libio.h _IO_BUFSIZ=_G_BUFSIZ
; and finally in _G_config.h _G_BUFSIZ=8192
%ifndef BUFSIZ
%define BUFSIZ 8192
%endif

;---------------------------------------------------
; standard streams
;---------------------------------------------------
; example usage:
; in C:         fputs(sentence, stderr);
; in asm        ccall fputs, sentence, dword[stderr]
;---------------------------------------------------
EXTERN stdin
EXTERN stdout
EXTERN stderr

;---------------------------------------------------
; C Functions
;---------------------------------------------------

; operations on files
EXTERN remove                   ;remove file
EXTERN rename                   ;rename file
EXTERN tmpfile                  ;open a temporary file
%ifdef __USE_UNSAFE_FUNCS__
EXTERN tempnam                  ;generate temporary filename
EXTERN tmpnam                   ;generate temporary filename
EXTERN tmpnam_r                 ;reentrant version of tmpnam
%endif

; file access
EXTERN fclose                   ;close file
EXTERN fflush                   ;flush stream
EXTERN fopen                    ;open file
EXTERN freopen                  ;reopen stream with different file or mode
EXTERN setbuf                   ;set stream buffer
EXTERN setvbuf                  ;change stream buffering

; formatted input/output
EXTERN fprintf                  ;write formatted output to stream
EXTERN fscanf                   ;read formatted data from stream
EXTERN printf                   ;print formatted data to stdout
EXTERN scanf                    ;read formatted data from stdin
EXTERN sprintf                  ;write formatted data to string
EXTERN sscanf                   ;read formatted data from string
EXTERN vfprintf                 ;write formatted variable argument list to stream
EXTERN vprintf                  ;print formatted variable argument list to stdout
EXTERN vsprintf                 ;print formatted variable argument list to string

; character input/output
EXTERN fgetc                    ;get character from stream
EXTERN fgets                    ;get string from stream
EXTERN fputc                    ;write character to stream
EXTERN fputs                    ;write string to stream
EXTERN getc                     ;get character from stream
EXTERN getchar                  ;get character from stdin
%ifdef __USE_UNSAFE_FUNCS__
EXTERN gets                     ;get string from stdin
%endif
EXTERN putc                     ;write character to stream
EXTERN putchar                  ;write character to stdout
EXTERN puts                     ;write string to stdout
EXTERN ungetc                   ;unget character from stream

; direct input/output
EXTERN fread                    ;read block of data from stream
EXTERN fwrite                   ;write block of data to stream

; file positioning
EXTERN fgetpos                  ;get current position in stream
EXTERN fseek                    ;reposition stream position indicator
EXTERN fsetpos                  ;set position indicator of stream
EXTERN ftell                    ;get current position in stream
EXTERN rewind                   ;set position indicator to the beginning

; error handling
EXTERN clearerr                 ;clear error indicators
EXTERN feof                     ;check end-of-file indicator
EXTERN ferror                   ;check error indicator
EXTERN perror                   ;print error message

%ifndef __UNISTD_INC__
EXTERN ctermid                  ;return the name of the controlling terminal
EXTERN cuserid                  ;return the name of the current user
%endif

%endif

btw those functions, gnu_get_libc_version  and the other one are in /usr/include/gnu/libc-version.h
« Last Edit: May 25, 2011, 11:12:22 PM by brethren »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2382
  • Country: us
Re: Nasm and C??
« Reply #7 on: May 26, 2011, 01:17:45 AM »
Ah, so they are. Don't all those unused EXTERNs make your filesize huge? Some people don't mind that, I guess. I'm a "small freak", myself...

Here's one that may (or may not) be of more use to the 'doze folk. A question was raised, "How do I find out the month in Linux?". I wrote an all-asm example for Linux (I think - can't find it now... I have a ctime() equivalent at 556 bytes) Someone - maybe Keith? - suggested strftime(). I wrote a really perverse "mixture of asm and C" - used system calls to find the time and print the result, but did the "hard parts" in C. :) This is my attempt to make it "portable". No idea if it works or not. Still works in Linux. I should point out, in case it isn't obvious, that there is no point whatsoever in doing this in asm!

Code: [Select]
; get month in Linux... attempt to make it portable :)
; mixed asm and C :)

; nasm -f elf timec.asm
; gcc -o timec timec.o
;
; nasm -f win32 timec.asm --prefix _
; gcc -o timec.exe timec.o
; should be similar for your compiler?


global main

extern gettimeofday
extern strftime
extern localtime_r
extern puts

;----------------------------------------------
; some structures for "time stuff"
; note that these are mere "typedefs" - no memory allocated

struc tv
    tv_sec resd 1
    tv_usec resd 1
endstruc

struc tz
    tz_minuteswest resd 1
    tz_dsttime resd 1          ; obsolete! do not use!
endstruc       

struc tm
    tm_sec resd 1              ; Seconds. [0-60] (1 leap second)
    tm_min resd 1              ; Minutes. [0-59]
    tm_hour resd 1             ; Hours. [0-23]
    tm_mday resd 1             ; Day. [1-31]
    tm_mon resd 1              ; Month. [0-11]
    tm_year resd 1             ; Year - 1900.
    tm_wday resd 1             ; Day of week. [0-6]
    tm_yday resd 1             ; Days in year.[0-365]
    tm_isdst resd 1            ; DST. [-1/0/1]
endstruc


%define OUTBUFSIZ 100h

section .bss

; reserve memory for our structures
    timeval resb tv_size
    timezone resb tz_size
    the_time resb tm_size
; etc...
    outbuf resb OUTBUFSIZ

section .data

; note that the "back apostrophes" allow us to use "\n" etc.
; a fairly "new" Nasm feature...
;
; as requested, the month.

;    the_format db `%B! :)\n`, 0

; or give strftime a bit more of a workout...

    the_format db `%A, %B %d, %G\n%l:%M %p - %D\n`, 0


;---------------------------------

section .text
main:

; find out what time it is

    push timezone
    push timeval
    call gettimeofday
    add esp, 4 * 2
   
; make C do the difficult long division

    push the_time ; tm structure to fill
    push timeval  ; tv structure to work from
    call localtime_r
    add esp, 4 * 2

; and the tedious text lookup...
   
    push the_time   ; tm structure to work from
    push the_format ; format string in strftime syntax
    push OUTBUFSIZ  ; max
    push outbuf     ; buffer to fill
    call strftime
    add esp, 4 * 4
   
; we can print it without C's help...
; but we won't :)

    push outbuf
    call puts
    add esp, 4 * 1

    ret
;--------------------------

Best,
Frank


Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: Nasm and C??
« Reply #8 on: May 26, 2011, 03:59:06 PM »
Quote
Don't all those unused EXTERNs make your filesize huge?

to test that everything works and there are no symbols being redefined i use a test file that drags everything in (everything that i've done so far, that is). it looks like this
Code: [Select]
%define __USE_UNSAFE_FUNCS__
%include "stdio.inc"
%include "stdlib.inc"
%include "errno.inc"
%include "ctype.inc"
%include "unistd.inc"
%include "fcntl.inc"
%include "string.inc"
%include "limits.inc"
%include "setjmp.inc"
%include "pwd.inc"
%include "grp.inc"
%include "misc/syscalls.inc"
%include "misc/macros.inc"
%include "sys/stat.inc"
%include "sys/uio.inc"
%include "sys/reboot.inc"
%include "gnu/libc-version.inc"

SECTION .text
cproc main, argc, argv, envp
;this is just a test file to check the
;files work without errors when everything
;is included
cendproc

that file comes out at about 40kb and once its stripped its down to 11kb, i can live with that :D

btw nice example, works fine here ;) i did assemble and then used strip to get the file size down and even then its still 3.1kb so for the convenience of using a mix of glibc/asm you're always going to pay a price
« Last Edit: May 26, 2011, 08:00:18 PM by brethren »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Nasm and C??
« Reply #9 on: May 26, 2011, 10:24:34 PM »
I think what frank means is, you're probably not going to use every one of those EXTERN'd procedures, so including them adds a bit of overhead. In NASMX we would handle this in INVOKE. Instead of putting 'EXTERN baka' in the headers, try creating a more dynamic CCALL macro. Like so:

Code: [Select]
%macro externdef 1-*
        %rep %0
                %define __%{1}_is_external
                %rotate 1
        %endrep
%endmacro

%macro ccall 1-*
        %ifndef __%{1}_defined
                %define __%{1}_defined
                %ifdef __%{1}_is_external
                        EXTERN %{1}
                %endif
        %endif

        %define __procedure_call %1

        %rep %0-1
                %rotate -1
                push %1
        %endrep

        call __procedure_call

        %if (%0-1)
                add esp, (%0-1)*4
        %endif

%endmacro

In the above, I've modified your ccall implementation and included a new 'externdef' macro which defines an external symbol for dynamic inclusion when referenced by the ccall macro. This will reduce overall generated code size and only requires you to substitute 'extern baka' for 'externdef baka' in your include files. :)

About Bryant Keller
bkeller@about.me

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2382
  • Country: us
Re: Nasm and C??
« Reply #10 on: May 26, 2011, 10:49:44 PM »
That's pretty much what I had in mind... instead of declaring "everything possible" as extern. But if Brethren wants his .inc files to match the C .h files... well that's what they do. As he says, there's a "price" (for everything!).

Unless I'm mistaken, some assemblers (Masm?) seem to exclude unused "extern"s, but Nasm puts 'em in if you say so. "strip" eliminates much of the "bloat" (but 11k for a file that "doesn't do anything" still seems a bit "beefy" to me). Do Windows users have an equivalent to "strip"?

Nice thing about being "the programmer" is that we have choices about that kind of thing!

Best,
Frank


Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: Nasm and C??
« Reply #11 on: May 27, 2011, 03:59:57 PM »
thank you so much:)that is an ingenius solution to the problem. when i said i could live with the extra file size the externs generated it was purely because i couldn't think of a solution myself :D

btw i've many questions for you two ;D and i'll be posting later

Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: Nasm and C??
« Reply #12 on: May 27, 2011, 08:45:52 PM »
my first question is how would you two handle C data types?

an example of what i mean is uid_t which is a dword sized data type, they are used for user id's

the problem i have is that storage for dwords in the .bss section use resd then in the data section you use dd and finally in the text section you use mov dword[somevar], 1

ideally i would like to use something like...
SECTION .bss
somevar resb uid_t

SECTION .data
anothervar uid_t 0

SECTION .text
mov uid_t[somevar], 0

is this even possible and if not what method would you use for c data types?

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 430
  • Country: us
Re: Nasm and C??
« Reply #13 on: May 27, 2011, 10:30:15 PM »
brethren,

for examples of what you are trying to do you should download the NASMX package and look at the example demos contained therein.
The work contained in that package provides a ton of features that you are free to learn from and even help us out simply by testing them and submitting ideas, bug reports, etc...

please visit http://www.asmcommunity.net/projects/nasmx/ and download and play around a bit ;)

Offline brethren

  • Jr. Member
  • *
  • Posts: 28
Re: Nasm and C??
« Reply #14 on: May 29, 2011, 09:33:29 PM »
thanks for the link rob, i've downloaded it and the few examples and inc files i've looked at seem to include everything i need and much, much more. theres just one small problem i've not been able to find much in the way of documentation except for the source and for me reading other programmers asm code is akin to reverse engineering :D

is there any documentation for the nasmx project?