English Amiga Board


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

 
 
Thread Tools
Old 06 April 2019, 11:03   #1
Fook42
Registered User

 
Join Date: Aug 2016
Location: germany
Posts: 48
amiga-gcc minimal output

Hello,

i'm using amiga-gcc from bebbo on a linux-machine.
with this i'm trying to create a simple program using only amiga-native calls and making it as small and clean as possible.

i compile with
Code:
m68-amigaos-gcc -noixemul -s -g0 -O2 -m68020 main.c
inside my code i am opening and closing all libraries manually and i also specified int __initlibraries=0;

but i noticed that the output still contains more than my code (i just had a look at the hex-dump).. and i also saw that all libraries i open manually are in the output 2 times (like dos.library, mathieeedoubbas.lib.. etc).

so it seems that the gcc adds the libs again although i want to do this.

what am i doing wrong? or is there an extra option to avoid this?

here is my main.c:
Code:
#define __NOLIBBASE__
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/mathieeesingbas.h>
#include <proto/mathieeedoubbas.h>
#include <proto/mathieeedoubtrans.h>

int __nocommandline=1;
int __initlibraries=0;



// needed for RawDoFmt:
STATIC CONST ULONG StuffChar[] = { 0x16c04e75 };

struct ExecBase     *SysBase;
struct DosLibrary   *DOSBase;
struct MathIEEEBase *MathIeeeSingBasBase;
struct MathIEEEBase *MathIeeeDoubBasBase;
struct MathIEEEBase *MathIeeeDoubTransBase;

int main(void)
{
    int     rc = 0;
    ULONG   freemem = 0;
    char    text[20];
    ULONG   array[2];
    //--------------------------------------------------
    SysBase  = *((struct ExecBase **)4);
    DOSBase  = (struct DosLibrary *) OpenLibrary("dos.library",0);
    MathIeeeSingBasBase   = (struct MathIEEEBase *) OpenLibrary("mathieeesingbas.library", 0);
    MathIeeeDoubBasBase   = (struct MathIEEEBase *) OpenLibrary("mathieeedoubbas.library", 0);
    MathIeeeDoubTransBase = (struct MathIEEEBase *) OpenLibrary("mathieeedoubtrans.library", 0);



    if ((DOSBase) && (MathIeeeSingBasBase) && (MathIeeeDoubBasBase) && (MathIeeeDoubTransBase))
    {

        while (!(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C))
        {
            freemem = AvailMem(MEMF_CHIP);
            array[0] = (ULONG) freemem;
            /* create output-string */
            (void) RawDoFmt("Chip: %10ld", &array, (void (*)(void))&StuffChar, text );


...



            Delay(50*2);
        }
    } else {
        Printf("failed to open libraries!!!\n");
        rc = RETURN_FAIL;
    }

    if (MathIeeeDoubTransBase) { CloseLibrary((struct Library *) MathIeeeDoubTransBase); }
    if (MathIeeeDoubBasBase)   { CloseLibrary((struct Library *) MathIeeeDoubBasBase); }
    if (MathIeeeSingBasBase)   { CloseLibrary((struct Library *) MathIeeeSingBasBase); }
    if (DOSBase)  { CloseLibrary((struct Library *) DOSBase); }

    return rc;
}
Fook42 is offline  
Old 06 April 2019, 11:13   #2
thomas
Registered User
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 5,845
I think the option you seek is -nostdlib. Without you still get the ANSI C library. This has nothing to do with AmigaOS libraries, it contains functions such as strcpy and so on.

BTW, your program will crash if dos.library fails to open because then you call Printf which is part of dos.library.
thomas is offline  
Old 06 April 2019, 16:56   #3
Fook42
Registered User

 
Join Date: Aug 2016
Location: germany
Posts: 48
Quote:
Originally Posted by thomas View Post
I think the option you seek is -nostdlib. Without you still get the ANSI C library. This has nothing to do with AmigaOS libraries, it contains functions such as strcpy and so on.
okay.. thank you !!!
now i run into problems like this:
Code:
/opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/../../../../m68k-amigaos/bin/ld: /tmp/ccUk9VnM.ltrans0.ltrans.o:(.text+0x56e): undefined reference to `__floatunsisf'
/opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/../../../../m68k-amigaos/bin/ld: /tmp/ccUk9VnM.ltrans0.ltrans.o:(.text+0x57a): undefined reference to `__muldf3'
maybe i need to change my float-calculations as well...
so i can not use something like float x = 1.623 * (float) y ?
i need to pick the multiplication routine from mathieee.. lib ?

Quote:
BTW, your program will crash if dos.library fails to open because then you call Printf which is part of dos.library.
.. yes.. right !! good point... so i can not print out anything if dos is missing?.. hmm.
Fook42 is offline  
Old 06 April 2019, 18:21   #4
Hedeon
PPC Hacker

 
Join Date: Mar 2012
Location: Leiden / The Netherlands
Posts: 1,042
Quote:
Originally Posted by Fook42 View Post
.. yes.. right !! good point... so i can not print out anything if dos is missing?.. hmm.

You could bring up an Alert (guru).
Hedeon is offline  
Old 06 April 2019, 18:54   #5
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 491
I don't know if it's possible opening dos library with required version of 0 to ever be able to fail. (Maybe when you don't have any memory left)

If you fail to open it though, you have (at least) two options:
1)
#define THISPROC ((struct Process *)(SysBase->ThisTask))
#define Result2(x) THISPROC->pr_Result2 = x
Result2(ERROR_INVALID_RESIDENT_LIBRARY);

Not very visible to user.

2)
Alert( AG_OpenLib | AO_DOSLib );
Pretty visible to user (with magic numbers with no meaning ofc)


To still be able to "pull" standard functions (like strlen) you can go with -nostartfiles at linking instead of -nostdlib.

Further to make your executable even more clean and mean you could not have any globals at all and allocate them on the heap. (thus having it "pure" and re-entrantable. you can have it resident)

Something like that

Code:
#include <proto/exec.h>
#include <proto/dos.h>
#include <exec/alerts.h>

#include <string.h>

struct globals {
  struct ExecBase *SysBase;
  struct DosLibrary *DOSBase;
  BPTR   Stdout;
};

#define SysBase gv->SysBase
#define DOSBase gv->DOSBase


STATIC const ULONG tricky=0x16c04e75; /* move.b d0,(a3)+ ; rts */
VOID myprintf(struct globals *gv, char *fmt,...) {
  unsigned char buf[256];
  STRPTR *arg = (STRPTR *)(&fmt+1);
  RawDoFmt((STRPTR) fmt, arg, (void (*)())&tricky, buf);
  Write(gv->Stdout, buf, strlen((char *)buf));
}



#undef SysBase
#undef DOSBase
int foo() {
  struct ExecBase *SysBase = (*((struct ExecBase **) 4));
  struct globals *gv;
  

  if (!(gv=AllocMem(sizeof(struct globals), MEMF_ANY))) {
    Alert( AG_NoMemory );
    return 20;
  }

  struct DosLibrary *DOSBase = (struct DosLibrary *)OpenLibrary((STRPTR)"dos.library",33);
  if (!DOSBase) {
    FreeMem(gv, sizeof(struct globals));
    Alert( AG_OpenLib | AO_DOSLib );
    return 20;
  }

  gv->SysBase = SysBase;
  gv->Stdout = Output();
  gv->DOSBase = DOSBase;


  float x = 1.623 * (float) 100;
  myprintf(gv, "Just a hello world. If you cast x to integer is: %ld\n", (int)x);

  FreeMem(gv, sizeof(struct globals));
  CloseLibrary((struct Library *) DOSBase);
  return 0;
}
This compiles to 356 bytes with a custom printf builtin. (it won't do floats though)

Attached you can find a buildable make based sample.
Attached Files
File Type: zip nostartup.zip (1.6 KB, 19 views)
alkis is offline  
Old 06 April 2019, 19:49   #6
Photon
Moderator

Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjรถ / Sweden
Posts: 4,733
Thomas answers so well and straight to the point. So I'm sure you're past this point but for what it's worth.

Here is the general information about Printf - see notes about default output as if it's not executed from a CLI/Shell window you have to open a window (to have something to print to, not really related to which Printf you prefer), and the length bug.

Opening resources as you need them is best practice, and sometimes you don't see how they'd fail but you check anyway.

If size requirements are very tight such as for an intro for an artificial size limit, some wisely selected checks as for opening dos.library might be skipped due to the "platform" - it's more or less expected that you've found all the ways to remove anything extraneous for it to impress for its size.

In that hacky spirit, when the binary is ready for release, you can remove the 0 longword ending the hunk in a hex editor to save 4 bytes.
Photon is offline  
Old 06 April 2019, 20:30   #7
Fook42
Registered User

 
Join Date: Aug 2016
Location: germany
Posts: 48
thank you all for the good advice!


i will try the approach from alkis .. this "global"-idea was new to me..


the code itself is not for an intro or something as great.. it just a small programm that should read some sensor-data, process it and generate an output... this is why i need float-support, (maybe) dos-lib and for sure the RawDoFmt processing...


have not yet figured out how to handle the floats right.. but i will .. for sure
Fook42 is offline  
Old 07 April 2019, 02:14   #8
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 491
Quote:
Originally Posted by Fook42 View Post
...
have not yet figured out how to handle the floats right.. but i will .. for sure
What do you mean "handle"? My sample "handles" floats and with no extra
amiga libraries (gcc integrated support). I've included a line that does float multiplication.
It just can't print them, cause RawDoFmt hasn't any float support.

If you want to print your floats then the libc and standard stdio's printf will do the trick.
alkis is offline  
Old 07 April 2019, 04:04   #9
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 491
Quote:
Originally Posted by alkis View Post
...
My sample "handles" floats and with no extra
amiga libraries (gcc integrated support). I've included a line that does float multiplication.
Nope. The compiler did constant folding. It's a mess. If you need to play with floats/doubles use the standard C library
alkis is offline  
Old 07 April 2019, 10:34   #10
Fook42
Registered User

 
Join Date: Aug 2016
Location: germany
Posts: 48
Quote:
Originally Posted by alkis View Post
Nope. The compiler did constant folding. It's a mess. If you need to play with floats/doubles use the standard C library
i found out that the compiler will include mathieeesingbas, mathieeedoubbas and mathieeedoubtrans when i use a "real" float-calculation
Code:
volatile int y = 32;
  float x = 1.623 * (float) y;
but.. if i open these math-libraries manually (like dos-lib).. the generated output will contain 2 times these library-names (and i guess also, it contains 2 times the opening)..

i added this after the dos-opening inside the main routine:
Code:
struct MathIEEEBase *MathIeeeSingBasBase   = (struct MathIEEEBase *)OpenLibrary((STRPTR)"mathieeesingbas.library",0);
struct MathIEEEBase *MathIeeeDoubBasBase   = (struct MathIEEEBase *)OpenLibrary((STRPTR)"mathieeedoubbas.library",0);
struct MathIEEEBase *MathIeeeDoubTransBase = (struct MathIEEEBase *)OpenLibrary((STRPTR)"mathieeedoubtrans.library",0);
-> here is part of the hexdump of the file with the double libs (note that dos-lib is not there twice!)

00000000 00 00 03 f3 00 00 00 00 00 00 00 03 00 00 00 00 |................|
00000010 00 00 00 02 00 00 00 a0 00 00 00 18 00 00 00 02 |................|
00000020 00 00 03 e9 00 00 00 a0 4e f9 00 00 00 dc 00 00 |........N.......|
00000030 16 c0 4e 75 4e 55 ff 00 48 e7 30 3a 28 6d 00 08 |..NuNU..H.0m..|
00000040 2c 5c 20 6d 00 0c 43 ed 00 10 47 ed ff 00 45 fa |,\ m..C...G...E.|
00000050 ff e0 4e ae fd f6 26 2c 00 04 24 0b 2f 0b 4e b9 |..N...&,..$./.N.|
00000060 00 00 02 3c 2c 54 22 03 26 00 4e ae ff d0 4c ed |...<,T".&.N...L.|
00000070 5c 0c fe e8 4e 5d 4e 75 64 6f 73 2e 6c 69 62 72 |\...N]Nudos.libr|
00000080 61 72 79 00 6d 61 74 68 69 65 65 65 73 69 6e 67 |ary.mathieeesing|
00000090 62 61 73 2e 6c 69 62 72 61 72 79 00 6d 61 74 68 |bas.library.math|
000000a0 69 65 65 65 64 6f 75 62 62 61 73 2e 6c 69 62 72 |ieeedoubbas.libr|
000000b0 61 72 79 00 6d 61 74 68 69 65 65 65 64 6f 75 62 |ary.mathieeedoub|
000000c0 74 72 61 6e 73 2e 6c 69 62 72 61 72 79 00 4a 75 |trans.library.Ju|
000000d0 73 74 20 61 20 68 65 6c 6c 6f 20 77 6f 72 6c 64 |st a hello world|
...
00000280 20 2f 00 08 22 2f 00 0c 4e ae ff 9a 2c 5f 4e 75 | /.."/..N...,_Nu|
00000290 6d 61 74 68 69 65 65 65 64 6f 75 62 62 61 73 2e |mathieeedoubbas.|
000002a0 6c 69 62 72 61 72 79 00 00 00 03 ec 00 00 00 07 |library.........|
000002b0 00 00 00 00 00 00 00 02 00 00 00 38 00 00 01 6c |...........8...l|
...
00000310 00 00 00 00 00 00 02 68 00 00 00 00 00 00 00 2c |.......h.......,|
00000320 00 00 00 00 00 00 00 48 6d 61 74 68 69 65 65 65 |.......Hmathieee|
00000330 64 6f 75 62 74 72 61 6e 73 2e 6c 69 62 72 61 72 |doubtrans.librar|
00000340 79 00 00 00 6d 61 74 68 69 65 65 65 73 69 6e 67 |y...mathieeesing|
00000350 62 61 73 2e 6c 69 62 72 61 72 79 00 00 00 03 ec |bas.library.....|

Last edited by Fook42; 07 April 2019 at 10:42.
Fook42 is offline  
Old 07 April 2019, 15:47   #11
Fook42
Registered User

 
Join Date: Aug 2016
Location: germany
Posts: 48
one more thing i found out:


if i declare the math-libs globally nothing changes about the double-opening.


but (!)
if i declare them globally AND set them to NULL there, only my openlib-calls will be used and i dont see the libs twice in the output-binary.


with this "solution" i will save ~150Byte .. because of not having double-initialization of libraries.
Fook42 is offline  
Old 10 April 2019, 18:12   #12
bebbo
botcher

 
Join Date: Jun 2016
Location: Hamburg/Germany
Posts: 393
My thoughts:

* I would not check for success after opening DOSBase, it's there, unless you specify a futile version, but 33 is always sufficient.
* You could spare the AllocMem/FreeMem by using a global variable and it ends up in BSS.
* use __entrypoint at your start function to omit push/pop of registers.

Here you go:
Code:
#include <proto/exec.h>
#include <proto/dos.h>
#include <exec/alerts.h>

#include <string.h>

struct globals {
  struct ExecBase *SysBase;
  struct DosLibrary *DOSBase;
  BPTR   Stdout;
} __g = {0};

// needed here to open/close libs
__asm(".equ _SysBase, __g");
__asm(".equ _DOSBase, __g+4");

// needed everywhere ->put into header
#define SysBase gv->SysBase
#define DOSBase gv->DOSBase

STATIC const ULONG tricky=0x16c04e75; /* move.b d0,(a3)+ ; rts */
VOID myprintf(struct globals *gv, char *fmt,...) {
  unsigned char buf[256];
  STRPTR *arg = (STRPTR *)(&fmt+1);
  RawDoFmt((STRPTR) fmt, arg, (void (*)())&tricky, buf);
  Write(gv->Stdout, buf, strlen((char *)buf));
}

__entrypoint int foo() {
  struct globals *gv = (struct globals *)&__g;
  SysBase = (*((struct ExecBase **) 4));
  
  DOSBase = (struct DosLibrary *)OpenLibrary((STRPTR)"dos.library",33);
  
  gv->Stdout = Output();

  float x = 1.623 * (float) 100;
  myprintf(gv, "Just a hello world. if you cast x to integer is: %ld\n", (int)x);

  CloseLibrary((struct Library *) DOSBase);
  return 0;
}

Last edited by bebbo; 10 April 2019 at 18:52. Reason: added da code
bebbo is offline  
Old 01 May 2019, 11:17   #13
bebbo
botcher

 
Join Date: Jun 2016
Location: Hamburg/Germany
Posts: 393
To get back to that: In my opinion, the simplest and most convenient way to get a tiny executable is the following:
  • use -fbaserel
  • use library auto opening
  • use an own simple startup code
  • optional switch to the standard startup code if your project grows...

The startup code
Code:
#include <proto/exec.h>

extern int main(void);
extern void __initlibraries();
extern void __exitlibraries();

APTR __sp;
register APTR __stkptr __asm("sp");
struct ExecBase * SysBase;

__entrypoint int __startup(void) {
  asm("lea ___a4_init,a4");
  __sp = __stkptr;
  SysBase = (*((struct ExecBase **) 4));
  __initlibraries();
  	
  return main();
}

static __attribute__((noinline)) void ___exit(int rc __asm("d0")) {
  __stkptr = __sp;
}
void exit(int rc) {
  __exitlibraries();
  ___exit(rc);
}
and the real program:
Code:
#include <proto/dos.h>
#include <string.h>

extern void exit(int);

BPTR   Stdout;
int N = 100;

STATIC const ULONG tricky=0x16c04e75; /* move.b d0,(a3)+ ; rts */
VOID myprintf(char *fmt,...) {
  unsigned char buf[256];
  STRPTR *arg = (STRPTR *)(&fmt+1);
  RawDoFmt((STRPTR) fmt, arg, (void (*)())&tricky, buf);
  Write(Stdout, buf, strlen((char *)buf));
}

void main() {
  Stdout = Output();

  float x = 1.623 * (float) N;
  myprintf("Just a hello world. if you cast x to integer is: %ld\n", (int)x);

  exit(0);
}
Use
Code:
CFLAGS=-Os -noixemul -fomit-frame-pointer -fbaserel -msmall-code
LDFLAGS=-nostartfiles  -noixemul -fbaserel
plus specify startup.o as first file to the linker.
Code:
m68k-amigaos-gcc -nostartfiles -s -noixemul -fbaserel -o nshello startup.o nshello.o
?
bebbo is offline  
Old 01 May 2019, 20:01   #14
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 491
whats the byte size of the executable on that bebbo?
alkis is offline  
Old 01 May 2019, 22:28   #15
bebbo
botcher

 
Join Date: Jun 2016
Location: Hamburg/Germany
Posts: 393
Quote:
Originally Posted by alkis View Post
whats the byte size of the executable on that bebbo?
1340 bytes
bebbo is offline  
Old 01 May 2019, 23:17   #16
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 491
kind of big, huh? malloc is pulled in?
alkis is offline  
Old 02 May 2019, 08:54   #17
bebbo
botcher

 
Join Date: Jun 2016
Location: Hamburg/Germany
Posts: 393
Quote:
Originally Posted by alkis View Post
kind of big, huh? malloc is pulled in?
It's not big - just consider all the pulled in math functions. It uses mathieeedoubbas.library and mathieeedoubtrans.library plus the mandatory conversion functions to convert float to int and back etc.p.p.

Are you comparing apples with pears?

EDIT:
if you replace
Code:
int N = 100;
with
Code:
#define N 100
you end up with 696 bytes.

Last edited by bebbo; 02 May 2019 at 09:13.
bebbo is offline  
Old 02 May 2019, 09:49   #18
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 48
Posts: 491
Ah, that makes sense.
alkis 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
AREXX - minimal requirements/setup? solarmon Coders. Scripting 24 13 January 2019 18:39
Minimal config for multiview jotd support.Apps 17 14 March 2016 22:38
Amiga GCC Where to find it? _ThEcRoW request.Apps 10 02 March 2006 00:44
A minimal request jobro Amiga scene 3 29 December 2005 03:24
Amiga GCC Where can i find? _ThEcRoW request.Apps 1 22 October 2005 18:17

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 11:24.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.
Page generated in 0.08845 seconds with 16 queries