-
Notifications
You must be signed in to change notification settings - Fork 2
/
libnix.texi
1391 lines (1085 loc) · 50.3 KB
/
libnix.texi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\input texinfo
@setfilename libnix.info
@settitle libnix - a static library for GCC on the amiga
@setchapternewpage odd
@ifinfo
This is libnix.texi the documentation of the libnix library.
Since this document is part of the libnix package it stands
under the same copyright as the library itself, i.e. it's
public domain.
@end ifinfo
@titlepage
@title libnix
@subtitle a static library for GCC on the amiga
@author Matthias Fleischer & Gunther Nikl
@end titlepage
@node Top,Description,(dir),(dir)
@ifinfo
This is the documentation of libnix. The following is a list
of chapters. You need not read all of them - but reading
the chapter Features is recommended.
@end ifinfo
@menu
* Description:: What is libnix?
* Authors:: Who did it?
* Disclaimer:: Copyright and other legal stuff.
* Naming:: Naming conventions.
* Usage:: How to use it ;-)
* Features:: Details of the implementation (and more).
* Special startups:: How to write shared libraries and devices with gcc.
* Set elements:: A nice feature of gnu ld.
* geta4:: Some words on code and data models
* Library bases:: And how they work.
* Code size:: How to write small programs with gcc
* FAQs:: Frequently asked questions and answers.
@end menu
@node Description,Authors,Top,Top
@chapter What is libnix?
libnix is a static (i.e. link) library for usage on amiga computers
together with gcc 2.3.3 or above. It is very amigalike and contains
a lot of features you probably don't want to miss:
@itemize @bullet
@item
auto-open-library feature
@item
SAS compatible handling of WB startup message
@item
auto-detach startup code
@item
is very short
@item
does not require a shared library
@item
auto stack-extend
@item
and much more
@end itemize
So if you want to write amiga specific programs or if you only need ANSI support
instead of unix compatibility - and if you don't want to redistribute ixemul.library -
this can be your choice.
But be aware - libnix requires Amiga OS 2.0 or higher :(.
@node Authors,Disclaimer,Description,Top
@chapter Authors
If you want to change anything in the library please contact one of us first -
we know how to do it best since we wrote it. If you want to report
bugs please contact us, too. If we don't know about them we cannot fix them.
Matthias Fleischer
@*fleischr@@izfm.uni-stuttgart.de
Gunther Nikl
@*gnikl@@informatik.uni-rostock.de
Special thanks go to Gerhard Müller for writing gerlib, Philippe Brand for
finding a name for this beast and Kriton Kyrimis who contributed some
of the non-ANSI functions and a lot of ideas.
@node Disclaimer,Naming,Authors,Top
@chapter Disclaimer
This package is public domain. That means that you can copy, use and modify it
without any problems and that you can get it for free. If you actually
paid for getting it this is completely your fault - I didn't see a cent
of that money. It also means that I cannot be made responsible for any damage
resulting out of the use of it - you simply shouldn't trust anything you didn't
pay for :-).
@node Naming,Usage,Disclaimer,Top
@chapter Naming conventions
This library is not only for the end user but also for the library
programmer (if you want to write your own startup, etc).
If you want to write code for it you should be aware of the normal
naming conventions for ANSI libraries:
@itemize @bullet
@item
Names with no underscore @samp{foo} are ANSI or POSIX compliant - there is absolutely
no risk in using them. If you use only these you can write portable
programs.
@item
Names with a single underscore @samp{_foo} are ANSI extensions for the
end user. Usually they are very common on certain systems but not used on
others.
@item
Names with two underscores @samp{__foo} are for the library programmers only.
If they are not documented you cannot rely on them. And even if they are
you should use them only for writing library code.
@end itemize
There is only one exception of these conventions (@samp{__chkabort()})
and this is for compatibility reasons.
@node Usage,Features,Naming,Top
@chapter Usage
The usage of this library is like any other link library. The only
important thing is the right linkage order:
@enumerate
@item
The startup code has to be used first :-)
@item
The stubs-library has to be used last since it contains the library base pointers.
@item
The commandline parser should be used after your code but before most
other things or you will run into problems.
@end enumerate
Normally this is handled by the specs file of gcc.
@code{gcc (-fbaserel) (-resident) -noixemul YOUR_OBJECTS (-lnix_main) (-lm)}
If you use @samp{-lnix_main} you get a different commandline parser.
@samp{-lm} uses the math library.
Be aware that the formatted I/O-functions need the math library
to work correctly for floating point numbers. Without the math
library you get only floating point support for simple operators
like @samp{+}, @samp{*}, casts and that like.
If you don't use the assembler inline functions of gcc you will have
to use @samp{libamiga.a} if you want to use any Amiga OS function.
gcc comes with a free version of libamiga.a which is a subset
of the original one. You can build it yourself if you unpack the sources,
but be prepared that it may take some time.
For compiling a4-relative programs you should choose the
@samp{-fbaserel} option. You get resident (pure) programs if
you set the @samp{-resident} option. Anything else necessary for these options
is handled by the specs-file (choosing the right startups and libraries).
If you (for some reason) don't trust you specs-file you can call everything
by hand:
@code{gcc -nostdlib ncrt0.o YOUR_OBJECTS libnixmain.a (libm.a) libnix.a
libstubs.a}
But that's not the recommended way. Therefore I don't explain this in
detail here - use the @samp{-v} option of gcc for more details.
@node Features,Special startups,Usage,Top
@chapter Features - what you get
The following list contains the elements of this package in
the right linkage order. This means if you follow the list from
top to bottom and take one file of each menu entry you will get
a working configuration.
@menu
* Startup codes:: Does all work necessary for startup.
Your objects Need I say anything about that?
* Commandline parser:: Calculates argc and argv.
libm.a The math library (optional).
* libstack.a:: Stack extension code (optional).
* libnix.a:: The library itself.
* libamiga.a:: If you have one.
* detach.o:: Auto detaching
* libstubs.a:: The library bases.
@end menu
@node Startup codes,Commandline parser,Features,Features
@chapter Startup codes
There is a lot of work to do before your @samp{main} function
can be called - open shared libraries, open stdin, stdout, etc.
Depending on the compiler options and the ANSI functions you use.
This work is done by the startup code.
@menu
* Startup interface::
* Startup usage::
@end menu
To get a short startup all the necessary modules are optional -
they get only linked in if you use them. There are 2 exceptions
from this (since the linker cannot check for it):
@itemize @bullet
@item
The commandline parser. It can be deactivated by declaring
@code{__nocommandline}
somewhere in your program (the type doesn't matter).
@item
The shared-library-opening module. You should not disable it unless
you know what you are doing since most library functions depend on it.
@end itemize
The startup codes itself are written in assembly to be as short as
possible.
Here is a little program to get the point:
@example
#include <inline/exec.h>
#include <dos/dos.h>
#include <inline/dos.h>
#include <workbench/workbench.h>
int __nocommandline=1; /* Disable commandline parsing */
int __initlibraries=0; /* Disable auto-library-opening */
struct DosLibrary *DOSBase=NULL;
extern struct WBStartup *_WBenchMsg;
int main(void)
@{ if(_WBenchMsg==NULL)
@{ if((DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37))!=NULL)
@{ Write(Output(),"Hello world\n",12);
CloseLibrary((struct Library *)DOSBase); @} @}
return 0;
@}
@end example
compiled and linked with
@code{gcc -noixemul -s -O2 -fbaserel helloworld.c}
gives an executable of 492 bytes. And this with the normal @samp{main}
function!
So you never need to try to write a program without a startup code.
@node Startup interface,Startup usage,Startup codes,Startup codes
@chapter Startup code interface
The startup codes do the following:
@itemize @bullet
@item
They catch the workbench startup message and place it into the
variable
@code{extern struct WBStartup *_WBenchMsg}
you can simply look into this place (and test for a @samp{NULL} pointer) to
check if your program was started from WB. If this is a @samp{NULL} pointer
@code{extern char *__commandline}
contains the (@samp{\n} terminated) parameters of the commandline.
@item
They call all functions in the
@code{long __INIT_LIST__[];}
with ascending priority.
@item
They call the function
@code{int main(int argc,char *argv[])}
You can exit by simply falling through the end of @samp{main} or by calling
@code{__volatile void exit(int returncode)}
which does the cleanup:
@item
It calls all functions in the
@code{long __EXIT_LIST__[];}
with descending priority.
@item
It replys the WB startup message if necessary, resets the stackpointer
and returns to the shell.
@end itemize
@samp{__INIT_LIST__} and @samp{__EXIT_LIST__} are two set elements
which are a speciality of the gnu ld. Since everything that needs
initialization works over these two lists the bare startups are
very short. In fact they are even shorter then some low-level-startups
You can easily add your
own functions to the startup procedure by using the macros
in the file @samp{headers/stabs.h} - but keep in mind that this
is non-portable. Priority values <=0 are reserved for library implementors.
@node Startup usage,,Startup interface,Startup codes
@chapter Startup code usage
There are currently 3 startup codes in this package (maybe there will be more
in the future). Depending on the code and data model you use and some other
things you should choose one of them:
@table @samp
@item ncrt0.o
This is the normal (i.e. large code, large data model) startup.
It contains a @samp{geta4()} entry point to enable you to use one source
for two code models. There is no other need for this function.
@item nbcrt0.o
This one is for compiling small data model (a4 relative) programs.
There is a @samp{geta4()} entry that places the right information into a4.
Use this startup code if you compiled with @samp{-fbaserel}.
@item nrcrt0.o
This startup code allocates a new data area every time you call it.
Even if you don't call it at all the data are is there once.
This gives you multientrant and reentrant code.
Therefore this startup code is for compiling resident (pure) programs.
Resident programs are always small data model if you let the compiler
do the work.
There is no @samp{geta4()} entry - I just don't know how this could be done.
(If you start your code 10 times and want to access global data
out of a hook you cannot tell which one of the 10 data areas to use
because you want to access the data from a different task!)
@end table
@node Commandline parser,libstack.a,Startup codes,Features
@chapter Commandline parser
There are currently 2 commandline parser modules in the libnix package.
You can easily write your own by looking into the examples
@table @code
@item libnixmain.a
This is the normal one, i.e. it does all the work necessary for
ANSI compatibility and gives you the normal @samp{main} calling
convention. You can shut down the commandline parsing (if you want
to use the amiga OS commandline parser) by declaring
@code{__nocommandline}
somewhere in your code (the type of it actually doesn't matter). This
spares some bytes and is compatible to every other compiler.
And you can declare your own WB shell window by declaring a
@code{char __stdiowin[]}
variable somewhere in your code (but only if you parse the commandline -
without the commandline parser you get no window at all!).
@item libnix_main.a
This is a special version of a commandline parser - it doesn't call
the normal @samp{main} but
@code{int main(char *commandline)}
@samp{commandline} is the complete commandline - including the quoted
filename of your program (it's only quoted, not escaped - this is
for compatibility reasons :-( ). You might think the name of the game
should be @samp{_main} and not @samp{main} - and you are completely
right. You can use @samp{_main} for @samp{main} and @samp{_exit} for
@samp{exit} - there are symbol redirections for these and the linker
does the work.
This commandline parser is useful for compatibility.
You can use it as a second example or for recompiling PD programs that
use the single argument. You cannot use it for compiling ANSI code.
@end table
@node libstack.a,libnix.a,Commandline parser,Features
@chapter special stack handling facilities
The current Amiga OS (V3.1) has a very limited stack handling compared
to most other OSs: Every process has it's own fixed sized stack - and that's
all about it. The usual default for this stack is 4k, but that's not enough
for more complicated purposes (like for example compilers). Setting a higher
default is no real solution because it costs a lot of (widely unused) memory
and may be overrun, too :-(.
But fortunately you can get stack extension with a little help of the compiler ;-).
Starting with V0.9 of libnix and V2.7.0 of gcc you get a fully featured stack
extension facility. The old stack swap method is still provided (not only for
compatibility but also because it's simpler) but please don't try to mix it with
the newer check/extend methods.
@menu
* swapstack:: Old method.
* stackextend implementation:: How stack extend works.
* stackextend usage:: Usage. @strong{read}
* Advanced:: Fine tuning.
* Costs:: Some damned lies (Benchmarks ;-) ).
@end menu
@node swapstack,stackextend implementation,libstack.a,libstack.a
@chapter Minimum stack setting
Most large tools need more stack than the default 4096 bytes. If your tool is
one of them you can either rely on the user being able to raise the current stack
or you can let libnix raise the stack for you. At startup this module checks if the
current stack is large enough for your needs and switches to a new one if not.
All you have to do is to provide a variable
@samp{unsigned long __stack=@{required stacksize@};}
somewhere in your code and to link with the appropriate swapstack.o module.
@node stackextend implementation,stackextend usage,swapstack,libstack.a
@chapter Implementation of stack checking and extension
The basic principle of stack checking is that the compiler emits special code
to check if the stack is large enough whenever there's need for a bigger chunk
of stackspace, i.e. at function entry when local arrays are allocated, at
the start of blocks with local variable sized arrays and when calling @samp{alloca()}.
If the needed stackchunk is bigger than the left stackspace the program ends.
Since this special code costs memory and CPU time smaller stackneeds (e.g. when
calling library functions) are handled by not really checking against the hard border
of the stackframe but against one that leaves a certain amount of stackspace left
(@xref{Advanced}.). If you like to call functions with a lot of arguments
(more than 256 bytes) you should raise this value.
Stack extension builds on the same basic principle but allocates a new stackframe
whenever necessary. If this happens at the entry of a function with arguments
they have to be copied to the new stackframe so that the function may use them.
Since C allows for a variable number of arguments the compiler doesn't always know
how many arguments there are. Therefore only a fixed number of bytes is copied.
If your functions may have lots of arguments (again more than 256 bytes) you
should raise this number.
Since allocation and freeing of memory through OS functions costs a lot of
time (while a stack tends to be very dynamic) libnix caches once used stackframes
and utilizes them again if necessary. The memory needed for this doesn't accumulate
or such but just sticks to a maximum value raised once. This may look like a memory leak
(while in fact it isn't). Be prepared for it.
@node stackextend usage,Advanced,stackextend implementation,libstack.a
@chapter Using stack checking or extension
To utilize the stack checking or extension feature you need at least V2.7.0 of
gcc. With this compiler you get 2 new amiga specific options that emit special
code whenever necessary:
@itemize @bullet
@item
@samp{-mstackcheck} Emits code that checks if there is enough stack left.
The program exits if not.
@item
@samp{-mstackextend} Tries to extend the stack before exiting (this may
happen due to low or fragmented memory).
@end itemize
Always use those switches together with @samp{-lstack} to link with the stack
extension code or you will get a lot of undefined references ;-).
You can mix functions compiled with or without stack checking and extention
without problems.
@strong{Caution:}
Do not use stack checking and/or extension switches when
compiling hook or interrupt code. Both run in alien contexts with a different
stack and all stack magic must fail. Also don't try to do some other stack magic
on your own if you want to use stack extension.
Also note that a program compiled with stack extension/checking may @samp{exit()} at
@emph{any} function entry or when using alloca or variable sized arrays. Either prepare
your cleanup function accordingly (use @samp{atexit()}) or don't use this feature.
If you like to write or call functions with more than 256 bytes of arguments
(64 ints, longs or pointers) you should adjust the behaviour of the
stack extension code (@xref{Advanced}.).
@node Advanced,Costs,stackextend usage,libstack.a
@chapter Stack extension fine tuning
To adjust the behaviour of the stack extension code to your personal needs
you may set some of the following variables (or functions)
@samp{unsigned long __stk_minframe} (default: 32768)
Minimum amount of memory to allocate for a new stackframe. Setting a higher
value speeds the code up but costs more memory if it is unused.
@samp{unsigned long __stk_safezone} (default: 2048)
Size of the safety zone. Set this to a higher value
if you want to @emph{call} functions with lots of arguments.
@samp{unsigned long __stk_argbytes} (default: 256)
Number of bytes copied as arguments. Set this to a higher
value if @emph{your} functions may have lots of arguments.
@samp{void _CXOVF(void)}
Is a user replaceable stack overflow handler. The default one just pops
up a requester, then exits. This function is not allowed to return.
@node Costs,,Advanced,libstack.a
@chapter Overhead of stack extension
The additional code needed for stack extension (or checking) costs memory
and CPU power. Here are some numbers to give you a very rough idea for it.
(Times are in 1/60s, sizes in bytes):
@example
Test normal checking extending extending
(big stack) (big stack) (big stack) (small stack)
Simple recursive
function runtime 152 221 225 226
(function calling
overhead)
Variable sized 52 136 398 468
array runtime
alloca runtime 31 118 118 118
Own code size 1040 1160 1140
Library code size 0 184 788
@end example
@node libnix.a,libamiga.a,libstack.a,Features
@chapter Some ANSI (mis)features
I suppose you are familiar with C and especially ANSI C - if not
you should read a good book about it
@footnote{I recommend this one:
Brian W. Kernighan, Dennis M.Ritchie:
@*The C Programming Language (Second Edition)
@*Prentice Hall, Englewood Cliffs, 1988}.
This chapter only contains some special features of the
implementation - you should know these if you want to
use this library.
@menu
* Locale::
* Formatted I/O::
* atof strtod::
* Memory management::
* Standard I/O::
* Signal handling::
* setjmp longjmp::
* ctype::
* clock::
* Multibyte character functions::
@end menu
@node Locale,Formatted I/O,libnix.a,libnix.a
@chapter Locale
One feature of a complete ANSI compatible library is locale support. The
ANSI standard only knows of two locales:
@itemize @bullet
@item
"C" locale (normal C behaviour).
@item
Default locale.
@end itemize
Every other locale depends very heavily on the implementation.
To do locale support on the amiga I decided to use locale.library (what else).
This means that you normally have only these two locales - to have more than that
you must make some extra preferences files with the locale preferences editor
and give the path of these to the setlocale()-call. If you do not have locale.library
you will get only "C" locale. This is the default then :-(.
Another important point is that the ANSI standard requires the default locale to be
loaded at program startup. i.e. if you use german locale (for example) you
will just get it - printf and scanf will not work as expected but use the
decimal comma @samp{,} instead of the decimal point @samp{.} for their floating
point numbers, ctype functions will behave differently, too.
This can be very annoying if you don't want to use ANSI locale but rather
locale.library (which is not portable but IMHO much better) or if
you don't need locale support. And even dangerous if you don't
test your program under different locales.
To get around this problem I decided to do some nasty thing:
To get locale support you have to make up a reference to setlocale. You can do
this by just calling
setlocale(LC_ALL,"C");
immediately after program startup. (And get "C" locale then after program start which
is a much better choice). Or by just using setlocale anywhere in your program -
you will get default locale at program startup then.
@node Formatted I/O,atof strtod,Locale,libnix.a
@chapter Formatted I/O
The formatted I/O specifications are all there (remember: this library tries to
be ANSI compliant). But there are two things you should know about them:
@itemize @bullet
@item
The formatted I/O is affected by the setlocale() call - this is no bug,
just an ANSI feature.
@item
Half of the code of a full blown printf handles floating point numbers -
but not everybody needs them. So there are two functions for both
@samp{vfprintf} and @samp{vfscanf} - one in @samp{libnix.a} not including
floating point support and one in @samp{libm.a} including floating
point support.
So if you want to use one of the formatted I/O specifiers for floats
you should link with the math library @samp{-lm}.
@end itemize
@node atof strtod,Memory management,Formatted I/O,libnix.a
@chapter atof strtod
The two functions @samp{atof} and @samp{strtod} require a working
@samp{%f} specifier in @samp{vfscanf} - therefore they
require the formatted I/O functions in the math library.
Since @samp{libm.a} is linked before @samp{libnix.a} these
two functions have been gone into the math library.
@node Memory management,Standard I/O,atof strtod,libnix.a
@chapter Memory management
Most of the memory management of this library runs through malloc().
Only the commandline parser uses AllocVec() - so you can use it without
having the malloc function somewere in your program.
The memory management uses a local (to this task) memory pool to reduce
memory fragmentation. It uses the system functions to do so (not the
new pooled memory functions but just the older Allocate(), Deallocate() pair
which are the <3.0 fallback for libamiga.a's pooled memory functions, too)
so there should be no problems with it - these functions are tested very good.
The default blocksize for memory allocations is 16384 bytes - equivalent
to 4 MMU pages. Bigger allocations are blown up to a multiple of 4096 bytes.
So don't be alarmed if your program uses more memory then expected.
If you don't like this value (if you use bigger portions frequently or only
use very little memory) you can replace it by declaring
@code{unsigned long _MSTEP}
You should use a multiple of MMU pages. If you don't use a full MMU page
you gain nothing - malloc rounds up anyway.
@node Standard I/O,Signal handling,Memory management,libnix.a
@chapter Standard I/O - where stdin, stdout, stderr come from
2 of the 3 standard I/O streams are no real problem:
@itemize @bullet
@item
@samp{stdin} is set to the value the @samp{Input()} function of @samp{dos.library}
serves,
@item
@samp{stdout} is set to the @samp{Output()} value.
@end itemize
Both streams are managed by the OS and the library need not take much
care about them. But @samp{stderr} is a different thing since
there is no @samp{Errput()} ;-) function. So @samp{stderr} is handled
as follows:
@enumerate
@item
If @samp{process->pr_CES} is set, this value is taken. There are not
much shells that set this value so most of the time this leads to NULL.
@item
If this didn't work and your program was started from CLI the library
opens @samp{Open("*",MODE_NEWFILE)}.
This opens the last interactive terminal attached to stdout, i.e.
if you use the normal Amiga shell and redirect your output to a file you
get the terminal, if you redirect your output to @samp{NIL:} you get @samp{NIL:}.
@item
If this didn't work too (you never know) or your program was started from WB
you simply get the same stream as in @samp{stdout}.
@end enumerate
@node Signal handling,setjmp longjmp,Standard I/O,libnix.a
@chapter Signal handling
There is only support for the two signals SIGABRT and SIGINT. The library
knows of some other signals but cannot generate them. The support for
SIGABRT is simple - but SIGINT is a completely different thing:
You cannot use exec signal handlers since they are called at any time -
even in the middle of a library call. And if your library just blocked
a private semaphore and you jump out of the library code you will get a nice
deadlock :-(. (And for people who don't know: signal handlers are bogus
upto OS 2.0 (even there you need a good setpatch)).
So SIGINT (CTRL-C) is just polled at the start of most I/O-functions by
calling the function
@code{void __chkabort(void)}
Other signals are even more difficult to implement:
@itemize @bullet
@item
SIGSEGV simply doesn't exist - and if it does it's due
to a VM system and should not be generated.
@item
SIGFPE is not generated by the math libraries - so it would
be a bad thing to generate it by the mathematical coprocessor.
@item
SIGILL should never happen - your program must be faulty if you get one.
Most of the time this happens if you try to run a 68020+ compiled program
on a plain 68000.
@item
SIGTERM couldn't be disabled - even if it was there ;-).
@end itemize
You can disable CTRL-C handling by replacing @samp{__chkabort} with a do-nothing
stub function - but there is a better way. Just call
@code{signal(SIGINT,SIG_IGN)}
Replacing __chkabort is used very often by amiga-programs and if
your application does not need CTRL-C handling at all and is
amiga specific you can use this. The second method is the
ANSI standard method and works on all types of machines.
@node setjmp longjmp,ctype,Signal handling,libnix.a
@chapter setjmp, longjmp
This library is compatible to the header files that come with gcc -
and the jmp_buf in there is not large enough for the FPU registers.
So they are not restored! The ANSI standard doesn't even require to
restore any of the other local variables (they are restored :-) ),
so this is NO incompatibility to the ANSI standard.
@node ctype,clock,setjmp longjmp,libnix.a
@chapter ctype.h functions
If you look into ctype.h you will see that the functions in there are
just macros - and that they are duplicate in the library as functions.
This is NOT a mistake. The ANSI standard requires such macros to be
duplicate as functions.
And remember: These functions are affected by the setlocale() call.
@node clock,Multibyte character functions,ctype,libnix.a
@chapter The clock function
The clock() function's work is to measure processor time for the specific
task - but there is no information like this in the amiga OS :-(.
So it just measures the time from program start on - and is compatible with
this behaviour to all single tasking OSs around.
@node Multibyte character functions,,clock,libnix.a
@chapter Multibyte character functions
The multibyte character functions are all there - but since the
Amiga OS uses no other character set than ECMA Latin I they simulate
just "C" locale. This means they do nothing useful.
@node libstubs.a,detach.o,libamiga.a,Features
@chapter libstubs - automatic library opening
The Amiga OS shared libraries are a nice thing. All the tasks can
use them in parallel, they eat up memory only if you use them and
they are simple to use - and all this works even without a
memory management unit (MMU).
Another nice feature is the fact that you can open them under
program control, i.e. you can take some action if they do not
exist - warn the user, disable some features, etc. This nice
feature becomes a misfeature if you only need a certain list
of functions that are there all the time - exec, dos, intuition -
you still have to open the shared libraries.
So most Amiga compilers have a feature called automatic library
opening feature. This means that all libraries you reference
(by calling one of the functions) but don't open yourself get
opened for you by the compiler.
@menu
* Auto-library-opening usage:: How to use it.
* Auto-library-opening interface:: How it works.
@end menu
@node Auto-library-opening usage,Auto-library-opening interface,libstubs.a,libstubs.a
@chapter Usage
To use this feature you have to do nothing (therefore it's called
automatic). But you can control the library version if you wish
by declaring
@code{long __oslibversion;}
somewhere in your program. But don't set this lower than 37 - most functions
of libnix (including the commandline parsers) need 37 or more.
@node Auto-library-opening interface,,Auto-library-opening usage,libstubs.a
@chapter Interface
Implementing such a feature is no hard work if you know how - this
implementation uses a (not so good known) feature of the gnu linker
called set elements:
@enumerate
@item
You write a library entry for every library base and link this library as the
last one. This means that the linker uses this library for every library base
pointer that is not defined but referenced somewhere.
@item
You tell the linker to collect these library bases together into a set element.
@item
You write a function that opens all libraries in the set element at
program start and cleans them up later.
@end enumerate
Some details:
There are two object files in the library for every library base pointer.
The first one is a
@example
struct lib
@{ struct Library *base;
char *name; @};
@end example
containing the library base pointer (a @samp{NULL} pointer at program start)
and a pointer to the name of the library. This name
@samp{extern char name[]}
is the second object. All these structs are collected together into one
single set element called
@samp{extern struct lib *__LIB_LIST__[]}
To open and close the shared libraries there are two functions in
libstubs:
@code{void __initlibraries(void)}
and
@code{void __exitlibraries(void)}
Since it is still possible to open the shared libraries by hand I had
to take care about the library base pointers for libnix itself -
they are used in the commandline parsers - even before anybody could
open them. There exists a (library private) duplicate library base
pointer for each of these. They have normal names with
two underscores in front.
So don't be alarmed if some system monitor tells you that your program
opened dos.library twice - this is normal behaviour, most libraries
do this.
Opening libraries by hand works exactly the same way as on any other compiler:
@itemize @bullet
@item
You declare the library base variable somewhere globally:
@code{struct DosLibrary *DOSBase=NULL;}
The initialization @samp{=NULL} is necessary! Uninitialized variables
get overwritten by initialized ones in other object files - and
the library base pointers in @samp{libstubs.a} are initialized with @samp{NULL}.
This is a feature of the GNU ld and I cannot do much about it :(.
@item
You open the library before using it:
@code{DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37);}
and do some action if it fails :).
@end itemize
@node detach.o,,libstubs.a,Features
@chapter Detaching from the current CLI
Some people like multitasking that much that they tend to start everything
in the background. Some tools are able to do this automatically - and with
libnix you can write such tools, too. @footnote{ Please be aware that you
lose the ability to synchronize your tool with the calling CLI - this can be
very nasty if one needs to. Use this feature very sparse: Most of the time
it's better to just rely on the user being able to type @samp{Run >NIL: <NIL:}. }
To be able to detach from the current CLI the detach module has to know
how much stack your program needs, how to call the new process, etc.
Therefore you will have to provide some global variables that contain this
information. If you don't provide them you will get default values
(don't blame me for them - it's your own fault :-@} ).
Here is an example set of variables:
@example
char *__procname="My nifty tool";
long __priority=-1; /* We don't eat that much processor time */
unsigned long stack=50000; /* but need a large stack */
@end example
@node Special startups,Set elements,Features,Top
@chapter Special startups
As a serious Amiga programmer you may sooner or later want to write your
own shared library or device. This can be a very difficult task if you never
did it before. To make your life easier we did some of the work for you
if you decide to use one of our startups. Be aware that writing a shared library
is a task for the experienced programmer @footnote{ Most ANSI library functions
don't work out of a shared library. libnix makes no difference here - even simple
operations like multiplying two integers can fail - don't take anything for granted.}.
@menu
* Calling convention:: How to interface to the system.
* libinit.o:: Shared library startup.
* libinitr.o:: Shared library with a new data segment for each caller.
* devinit.o:: Device startup.
@end menu
@node Calling convention,libinit.o,Special startups,Special startups
@chapter Calling convention
On the amiga almost all shared libraries are called with the library base
in a6 and other parameters in other registers. The result is placed in d0
usually.
If you want to write your own shared library you should stick to this model
to make it easier for others to interface with it - but unfortunately gcc
doesn't support registerized parameters. The solution to this problem is to
write an assembler wrapper for each function you need. Since all those
wrappers look the same it's easy to simplify their notation by using
preprocessor macros. You can find appropriate macros in the stabs.h file of
the libnix sources. Usage:
@example
/* Define some function that has 1 argument in d0 */
ADDTABL_1(__UserFunc,d0);
@end example
As a bonus these macros add your function to your library's jump vector.
All you have to do is to care for the right linkage order. And don't forget
to add a @samp{ADDTABL_END();} at the end of the vector.
Attention: Other programmers may decide to patch into your library's jump
vector - therefore it's a good idea to call even own functions over this
vector. To achieve this you have to provide some inline functions
(like those in the gnu:os-include/inline directory) or glue code and you have
to privatize the function's name by adding some '__'s or similar. You will
also have to set up your OWN library base.
@node libinit.o,libinitr.o,Calling convention,Special startups
@chapter Shared library startup
This startup gives you one data segment for all possible callers.
You will have to use semaphores to share special data between them.
To write a shared library you will have to provide some global variables
@example
const BYTE LibName[]="simple.library";
const BYTE LibIdString[]="version 1.0";
const UWORD LibVersion=1;
const UWORD LibRevision=0;
@end example
as well as some special functions
@footnote{It'll be possible to add an Open() and Close() function, too. But this
would be incompatible to libinitr.o and wouldn't give any advantages over this
method.}
@example
int __UserLibInit(struct Library *myLib);
void __UserLibCleanUp();
@end example
Please look into the examples directory for more details.
@node libinitr.o,devinit.o,libinit.o,Special startups
@chapter Shared library with different data segments
If you don't like the hassle with semaphores you can use this startup.
It provides a new data segment for each task that opens your library.
There are two disadvantages over libinit.o:
@itemize @bullet
@item
This method needs more memory.
@item
You cannot interact between your tasks.
@end itemize
The usage stays the same.