Author Topic: Linking to C  (Read 16994 times)

Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Linking to C
« on: July 13, 2010, 09:45:34 PM »
Looking around, I finally found something that explains a little about linking asm to C. (found something here which led to a bigger page elsewhere)

I found this (after adapting to Nasm):
Code: [Select]
#include <stdio.h>

int maxofthree(int, int, int);

int main() {
    printf("%d\n", maxofthree(1, -4, -7));
    printf("%d\n", maxofthree(2, -6, 1));
    printf("%d\n", maxofthree(2, 3, 1));
    printf("%d\n", maxofthree(-2, 4, 3));
    printf("%d\n", maxofthree(2, -6, 5));
    printf("%d\n", maxofthree(2, 4, 6));
    return 0;
}

and
Code: [Select]
global   maxofthree

section .text
maxofthree:
   mov   eax, [esp+4]
   mov   ecx, [esp+8]
   mov   edx, [esp+12]
   cmp   eax, ecx
   cmovl   eax, ecx
   cmp   eax, edx
   cmovl   eax, edx
   ret

Which makes sense to me.

But this one works but I don't understand the message: part

Code: [Select]
$ cat helloworld.asm
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
; ----------------------------------------------------------------------------

        global  main
        extern  printf

        section .text
main:
        push    message
        call    printf
        add     esp, 4
        ret
message:
        db      'Hello, World', 10, 0


Is the message part proper syntax for Nasm? It seems to lack a name.

I saw several other examples with a data part like that

Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Re: Linking to C
« Reply #1 on: July 14, 2010, 12:19:09 AM »
I'm still curious if there is a problem with the above code, even though it works fine.
But I see that following regular Nasm style definitely works fine

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Linking to C
« Reply #2 on: July 14, 2010, 12:42:19 AM »
Yeah... a "label", like "main", and a "variable name", like "message", are actually the same thing - just the address of the next byte. Either can go on the same line, or on the preceeding line by itself. The colon is optional, in either case. Nasm will "warn" about "label alone on a line without a colon", but it still assembles your code. This is a "suppressible warning", and was turned off by default in earlier versions... but if you intend "lodsb" and write "lodbs", Nasm would take the latter as a label, and the intended instruction would just "disappear" without warning. So in recent versions, it's turned on by default. Sort of a half-baked spell checker. :)

I prefer variable names on the same line, without a colon, and labels on a separate line with a colon, but it's just a matter of style. You can mix-and-match as you wish. Older Nasm code may generate a "label alone on a line" warning - some people did it like that. You can ignore the warning, or turn it off, or add the colon. Programmer's choice!

Since you're linking with C, you might want to know about another fairly new feature. If you enclose your text with "back apostrophes" (back-ticks, back quotes) instead of the usual single or double quotes, Nasm will accept "\n" and the other standard C "escapes".

Code: [Select]
message db `Hello World!\n`, 0

Another "tip" you might run into: printf always expects "floats" (%f) to be doubles (qword), even if they're declared as "float" (dword). This can result in some strange numbers - and other troubles - if you don't know about it! :)

Code: [Select]
; nasm -f elf hwfloat.asm
; gcc hwfloat.o -o hwfloat
; ./hwfloat
; echo $? to see "answer"

global main
extern printf

section .data
    hello_string db 'Hello, World!', 0
    the_int dd 42
    the_float dd 42.0  ; single precision
   
    format_string db 'The string is "%s"', 10
db 'The float is: %f', 10
db 'The int is: %d', 10, 0

section .text
    main:

; printf("the string is %s\nthe float is: %f\n the int is: %d",
;        hello_string, the_float, the_int);
;
; push rightmost parameter first...
    push dword [the_int]
; printf quietly promotes floats to doubles(!)
; so we'll want 8 bytes on the stack
    sub esp, 8

; now put our float there, as double
    fld dword [the_float]
    fstp qword [esp]
; and the leftmost parameter...
    push hello_string
; and the format string last
    push format_string
    call printf
    add esp, 4 * 3 + 8

; "main" returns int (right???)
; zero is the usual "no error" exitcode, but
; return something "identifiable", just for fun
    mov eax, 42
   
    ret

We could also do it - if the "float" were declared as double-precision - in two pushes:

Code: [Select]
section .data
   my_double dq 42.0
   format_string db `Answer: %f\n', 0

section .text
   push dword [my_double + 4]
   push dword [my_double]
   push format_string
   call printf
   add esp, 12

(note that the decimal point tells Nasm we want a "float" not an integer)

Nasm is very flexible, and getting better all the time! :)

Best,
Frank


« Last Edit: July 14, 2010, 08:59:39 AM by Frank Kotler »

Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Re: Linking to C
« Reply #3 on: July 14, 2010, 01:42:45 PM »
Thanks, and the two bonus answers are great to know.
I saw some float examples that didn't work right, I will look over them again.