English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Language > Coders. C/C++

 
 
Thread Tools
Old 10 November 2015, 17:12   #1
Nosferax
Registered User
 
Join Date: Apr 2015
Location: Beauharnois,Qc,Canada
Posts: 227
Calling assembler functions from C

Let say I write an assembler routine that does some function and I want to call it from within a C program, how would I do that with VBCC or the other most common Amiga C compiler (I don't mind using SAS or other compilers).

Anyone got an example?
Nosferax is offline  
Old 10 November 2015, 17:56   #2
thomas
Registered User
 
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 7,026
Make sure that the name of the assembler routine is declared as global symbol and that the name starts with a _. Then you can call it from the C program without the _.

for example:

Code:
_the_answer:
	move.l	#42,d0
	rts

	public	_the_answer
Code:
#include <stdio.h>

long the_answer (void);

int main (void)
{
long a = the_answer();
printf ("the answer is %ld\n",a);
}

Note that if you change any register except d0 and d1, you have to restore the previous contents before your asm routine exits.


You might compile a small C program with the -S option to get the assembler output from the compiler. Then you can see how a subroutine is defined in assembler.

For example
Code:
vc -S test.c -o test.asm

Last edited by thomas; 10 November 2015 at 18:02.
thomas is offline  
Old 10 November 2015, 19:27   #3
Nosferax
Registered User
 
Join Date: Apr 2015
Location: Beauharnois,Qc,Canada
Posts: 227
Oh! Thank you!
Nosferax is offline  
Old 10 November 2015, 19:30   #4
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 722
Quote:
Originally Posted by thomas View Post
Note that if you change any register except d0 and d1, you have to restore the previous contents before your asm routine exits.
Umm, aren't d0-d1/a0-a1 the 'scratch' registers?
alkis is offline  
Old 11 November 2015, 08:39   #5
punktniklas
 
Posts: n/a
Isn't this example a bit simplified since the_answer() doesn't take any arguments? In a normal C function call the arguments would be passed on the stack and not in CPU registers, which a typical assembler routine would prefer.

There are compiler directives you can use to make it use registers instead. In SAS/C it's something like

long __asm the_answer(__register d0 long foo);

(It's been a long time since I did this.. :-) )
 
Old 11 November 2015, 16:59   #6
thomas
Registered User
 
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 7,026
Quote:
Originally Posted by alkis View Post
Umm, aren't d0-d1/a0-a1 the 'scratch' registers?
Maybe. But it hurts more if you miss to save a needed register than if you save a scratch register.


Quote:
Originally Posted by punktniklas View Post
Isn't this example a bit simplified since the_answer() doesn't take any arguments?
Sure, my reply wasn't meant as an overall comprehensive answer, it concentrated only on the way names are matched between Asm and C.

Here is another strongly simplified example, but this time with arguments:

Code:
_add:
	add.l	d1,d0
	rts

	public _add
Code:
#include <stdio.h>

long add (__reg("d0") long a,__reg("d1") long b);

int main (void)
{
long a = add(14,16);
printf ("14 + 16 = %ld\n",a);
}
Note that the register notation is compiler-specific. If you want to stay compiler-independent, you should keep the arguments on the stack like the compiler does it with C subroutines, too.

Code:
_add:
	move.l	4(sp),d0
	add.l	8(sp),d0
	rts

	public _add
Code:
#include <stdio.h>

long add (long a,long b);

int main (void)
{
long a = add(14,16);
printf ("14 + 16 = %ld\n",a);
}
Note that 0(sp) is the return address.

Also note that arguments are put on the stack in reverse order so that they appear in memory in the correct order. This means that 4(sp) corresponds to argument a and 8(sp) to argument b.
thomas is offline  
Old 13 November 2016, 20:08   #7
arti
Registered User
 
Join Date: Jul 2008
Location: Poland
Posts: 665
How can I link vasm compiled code with gcc ?
arti is offline  
Old 13 November 2016, 20:53   #8
hitchhikr
Registered User
 
Join Date: Jun 2008
Location: somewhere else
Posts: 524
Afaik gcc handles objects produced with vasm (using -Fhunk in vasm command line).
hitchhikr is offline  
Old 13 November 2016, 21:02   #9
arti
Registered User
 
Join Date: Jul 2008
Location: Poland
Posts: 665
Yes!
arti is offline  
Old 13 November 2016, 22:46   #10
hitchhikr
Registered User
 
Join Date: Jun 2008
Location: somewhere else
Posts: 524
The advantage of working with gcc + vasm instead of gcc + as is that you can create chipmem hunk in your executable by using (in asm):

Code:
section ".data_chip",data
(i don't know if it's possible with gnu as).
hitchhikr is offline  
Old 14 November 2016, 13:08   #11
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,541
Quote:
Originally Posted by hitchhikr View Post
Afaik gcc handles objects produced with vasm (using -Fhunk in vasm command line).
Depends on the gcc-port. Some only support a.out format, in which case you have to make vasm output a.out format as well: -Faout.

Quote:
Originally Posted by hitchhikr View Post
The advantage of working with gcc + vasm instead of gcc + as is that you can create chipmem hunk in your executable by using (in asm):

Code:
section ".data_chip",data
This directive would not set the Chipmem-Flag. You have to add ",chip":
Code:
        section ".data_chip",data,chip
phx is offline  
Old 14 November 2016, 13:20   #12
hitchhikr
Registered User
 
Join Date: Jun 2008
Location: somewhere else
Posts: 524
I use gcc version 3.4.0.

No, data_c or data,chip won't work with gnu-ld, the linker uses the name of the section to relocate it to chipmem so it have to be ".data_chip",data (anything else won't work).
hitchhikr is offline  
Old 14 November 2016, 14:47   #13
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,541
Ok. Didn't know that. I thought that GNU-ld would be able to evaluate the memflags, when it already supports hunk-format.
phx is offline  
Old 14 November 2016, 19:33   #14
arti
Registered User
 
Join Date: Jul 2008
Location: Poland
Posts: 665
I can't compile this line in gcc (3.4.0):
Code:
long add (__reg("d0") long a,__reg("d1") long b);
Code:
add.c:3: error: syntax error before '(' token
add.c: In function `add':
add.c:3: error: syntax error before string constant
add.c:6: error: syntax error before '{' token
Tried __asm("d0") and register __d0 with no luck too.

Last edited by arti; 14 November 2016 at 20:10.
arti is offline  
Old 14 November 2016, 21:02   #15
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 722
Quote:
Originally Posted by arti View Post
I can't compile this line in gcc (3.4.0):
Code:
long add (__reg("d0") long a,__reg("d1") long b);
Code:
add.c:3: error: syntax error before '(' token
add.c: In function `add':
add.c:3: error: syntax error before string constant
add.c:6: error: syntax error before '{' token
Tried __asm("d0") and register __d0 with no luck too.
try
Code:
register long a __asm("d0")
alkis is offline  
Old 15 November 2016, 01:30   #16
matthey
Banned
 
Join Date: Jan 2010
Location: Kansas
Posts: 1,284
Every compiler has its own syntax for assembler and register calling. There was an attempt years ago to make a universal syntax using macros for most of the common Amiga compilers. Vbcc was rather difficult to get working as macros don't like the characters vbcc requires for defining registers but I found a trick to get it working. It should now support GCC, vbcc, SAS/C, DICE and even the old Storm C. My contributions build on those from others. The test example is based on Thomas's example and is very simple. There is an AmigaDOS script to make the simple project using vbcc. I have not tested with other compilers so let me know if it doesn't work somewhere. Ideas for improvement are also welcome and it would be interesting to hear who came up with the original idea. See the attachment for the archive.

Edit: New version attached with GCC and vbcc tests. I believe it will only work with unofficial Amiga GCC versions like GCC 2.95.3 and 3.4.0. It was necessary to change the required syntax slightly (less readable but not too bad IMO). Needs testing and possibly fixes for other Amiga compilers. Let me know if there are problems and send me any fixes.
Attached Files
File Type: lha asm_call.lha (1.1 KB, 256 views)

Last edited by matthey; 15 November 2016 at 18:39.
matthey is offline  
Old 15 November 2016, 14:18   #17
arti
Registered User
 
Join Date: Jul 2008
Location: Poland
Posts: 665
Great stuff matthey.
But still no go for gcc:

Parse error before long a
Code:
long add( REG(d0) long a, REG(d1) long b );

Last edited by arti; 15 November 2016 at 15:20.
arti is offline  
Old 15 November 2016, 17:28   #18
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 722
You didn't tried, did you?

Ok, let's see.

Code:
m68k-amigaos-gcc --version
m68k-amigaos-gcc (GCC) 3.4.0
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

cat foo.c
long add (register long a __asm("d0"), register long b __asm("d1"));
m68k-amigaos-gcc -c foo.c
No errors.
alkis is offline  
Old 15 November 2016, 17:36   #19
matthey
Banned
 
Join Date: Jan 2010
Location: Kansas
Posts: 1,284
Quote:
Originally Posted by arti View Post
Great stuff matthey.
But still no go for gcc:

Parse error before long a
Code:
long add( REG(d0) long a, REG(d1) long b );
I can verify the problem with GCC 3.4.0. I have done some more research and testing. The line that works in the unofficial (GeekGadgets) GCC looks like it would be the following.

Code:
long add( register long a __asm("d0"), register long b __asm("d1") );
I could not find a way for newer official versions of GCC to specify the registers to functions. The target ABI is used by default.

The macros I provided do not work for GCC (someone else created them). Maybe this is another reason why the macros did not become popular. I can get the macros to generate the correct text but the __asm("reg") part is before each variable which does not work. I may have to change how the macros work to allow a universal definition and then it still is unlikely to work with newer official GCC compilers .
matthey is offline  
Old 15 November 2016, 17:47   #20
arti
Registered User
 
Join Date: Jul 2008
Location: Poland
Posts: 665
I've tried this order ->
Code:
register __asm("d0") long a
But this works ->
Code:
register long a __asm("d0")
On 3.4 only, but that's ok for me.

Last edited by arti; 15 November 2016 at 17:53.
arti is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Replacing OS4 functions for OS3.x arti Coders. C/C++ 25 17 December 2018 16:03
functions benchmark wawa Coders. System 2 15 April 2013 18:55
How do the non-i/o functions work? mikro project.WHDLoad 3 03 November 2011 14:33
Lost F key Functions on WINuae startup breadbaker support.WinUAE 8 06 December 2005 20:09
CD32 blue button functions differently oldpx support.WinUAE 6 09 August 2004 13:43

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 13:18.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.10953 seconds with 14 queries