Creating library documentation needs an update

Requests for features
Post Reply
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Creating library documentation needs an update

Post by DarkSchneider »

I am interested in moving the code to library format so only the required parts are linked. I have seen:

https://www.z88dk.org/wiki/doku.php?id= ... g_libaries
viewtopic.php?id=2637

And I think is not updated. Some points:

- Don't mention how to mix with C functions in the library.
- Using different directives in each case.
- Can a library be created with zcc instead z80asm? If we want to mix asm and C.
- Something not updated:
the C compiler can only call functions through function pointers using standard C linkage
I currently have function pointers prototypes using the __z88dk_fastcall and working correctly, so I suppose that now is supported.
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Creating library documentation needs an update

Post by dom »

I actually don't think I've written any documentation on how to create a 3rd party library from classic. The links you've got are for newlib, though the principles are the same. If I get some time I'll write a few words.

The classic library is made of a mixture of C and asm files so it's possible, just compile to .o files and then use z80asm to create the library.

Decorated function pointers are "fun", it's true that sccz80 does support fastcall function pointers (though at a bit of register juggling cost - it probably could be done better), though last time I tested sdcc doesn't.
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

Well, with the main code already "finished" (only requiring some final attunement) it's time to split it into individual parts to allow smaller binary linking only the required.
Let's say I have this folder structure:

Code: Select all

root
|
|-src
|
|-test
I am compiling from test folder. Looking at documentation:
https://www.z88dk.org/wiki/doku.php?id= ... g_libaries
Seems that I have to create a folder for each library (i.e. input), split into one file per function, put all them into the folder, and put the lst and generated library file at src folder. Then for compiling from test I'd can do it using -L../src -linput i.e. for input library.

But, looking at:
the C compiler can only call functions through function pointers using standard C linkage
The preprocessor does not make the callee substitution because the number of parameters doesn't match. In this case the library function “sp1_IterateSprChar” is called using normal C linkage. You can see that this function is only a shell that calls into the real callee function
I will keep some functions in the original source format, those are:
- Non-standard C linkage functions called as pointer: I prefer not to use "shell that calls into the real callee function" but directly the callee.
- Functions dependant of preprocessor that could vary, as have some functions that depends of some #define that can change from one compilation to another for the final binary (I think this should be done using external definitions in command line).

Not sure if I miss something.
User avatar
jorgegv
Well known member
Posts: 287
Joined: Wed Nov 18, 2020 5:08 pm

Re: Creating library documentation needs an update

Post by jorgegv »

dom wrote: Thu Apr 27, 2023 8:54 am Decorated function pointers are "fun", it's true that sccz80 does support fastcall function pointers (though at a bit of register juggling cost - it probably could be done better), though last time I tested sdcc doesn't.
Mmm I have been using __z88dk_fastcall function pointers in RAGE1 since the beginning, with sdcc... That's at least two years ago...
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

But from a library made by yourself?

The z88dk included ones can use the trick indicated at link, that is using a wrapper, which I’d prefer to avoid.
User avatar
jorgegv
Well known member
Posts: 287
Joined: Wed Nov 18, 2020 5:08 pm

Re: Creating library documentation needs an update

Post by jorgegv »

No wrapper. The functions are called vía pointers with arg in HL and the receiving functions just use HL as It comes. I think I checked the generated assembly at the time...
User avatar
jorgegv
Well known member
Posts: 287
Joined: Wed Nov 18, 2020 5:08 pm

Re: Creating library documentation needs an update

Post by jorgegv »

jorgegv wrote: Tue May 30, 2023 1:55 pm No wrapper. The functions are called vía pointers with arg in HL and the receiving functions just use HL as It comes. I think I checked the generated assembly at the time...
I'm declaring the function pointers this way:

Code: Select all

// Dispatch tables for rule checks and actions
typedef uint8_t (*rule_check_fn_t)( struct flow_rule_check_s * ) __z88dk_fastcall;
typedef void (*rule_action_fn_t)( struct flow_rule_action_s * ) __z88dk_fastcall;
The functions are called from here (see the relevant lines where rule_check_fn and rule_action_fn appear, inside the loops):

Code: Select all

    for ( i = 0; i < t->num_rules; i++ ) {
        struct flow_rule_s *r = t->rules[i];
        // run the checks in order, skip to next rule as soon as one check returns false
        for ( j = 0; j < r->num_checks; j++ ) {
            check = &r->checks[j];
            if ( ! rule_check_fn[ check->type ]( check ) )
                goto next_rule;
        }
        // if we reach here, all checks were true, or there were no checks; run the actions in order
        for ( j = 0; j < r->num_actions; j++ ) {
            action = &r->actions[j];
            rule_action_fn[ action->type ]( action );
        }
    next_rule:
        continue;
    }
The generated asm for one of those functions is:

Code: Select all

  1284                          ;engine/src/flow.c:122: uint8_t do_rule_check_game_flag_is_set( struct flow_rule_check_s *check ) __z88dk_fastcall {
  1285                          ;       ---------------------------------
  1286                          ; Function do_rule_check_game_flag_is_set
  1287                          ; ---------------------------------
  1288                          _do_rule_check_game_flag_is_set:
  1289  015a  eb                        ex      de, hl
  1290                          ;engine/src/flow.c:123: return ( GET_GAME_FLAG( check->data.flag_state.flag ) ? 1 : 0 );
  1291  015b  212e00                    ld      hl,+(_game_state + 46)
  1292  015e  4e                        ld      c, (hl)
  1293  015f  13                        inc     de
  1294  0160  1a                        ld      a, (de)
  1295  0161  a1                        and     a,c
  1296  0162  2805                      jr      Z,l_do_rule_check_game_flag_is_set_00103
  1297  0164  210100                    ld      hl,0x0001
  1298  0167  1803                      jr      l_do_rule_check_game_flag_is_set_00104
  1299                          l_do_rule_check_game_flag_is_set_00103:
  1300  0169  210000                    ld      hl,0x0000
  1301                          l_do_rule_check_game_flag_is_set_00104:
  1302                          ;engine/src/flow.c:124: }
  1303  016c  c9                        ret
As I said, everything works fine with SDCC since years ago, and the params for the function pointers are indeed being passed and received via HL.
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

Yes that is what I do also, but not tested yet with own library functions. Seems then that if declaring with typedef it uses the correct calling at compile time even if function pointer.
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

Well made my first library. Now it has changed, starting with the own z80asm:
https://github.com/z88dk/z88dk/wiki/Tool---z80asm
... as librarian
z88dk-z80asm -xlibrary.lib [options] file...
When called with the -x option, z80asm builds a library containing all the object files passed as argument. That library can then be used during linking by specifying it with the -l option.
In this example we take the typical folder layout:

Code: Select all

lib
|
|- mylib1
|- mylib2
So now you put all your individual files into your library folder, in my example all are C source files, then compile with:

Code: Select all

lib/mylib1$ zcc +platform [options] -c *.c -I/your/include/folder
This output to .o files.
Then from the your main lib folder and create the library file:

Code: Select all

lib$ z88dk-z80asm -xmylib1.lib mylib1/*.o
Not tested but I suppose if we have a mix we could simply pass as files: *.o *.asm

Now to compile our program with our library:

Code: Select all

$ zcc +platform [options] -L/your_library_folder -lmylib1 .....
But some things are not clear for me, like using the __LIB__ qualifier, according to old documentation:
The __LIB__ qualifier will cause the C compiler to translate these header functions into sequences of “LIB myfunc”, “LIB init”, etc so that the linker will know those references are for library functions. The C compiler will generate code like “call myfunc” and “call init” to call these functions.
With some examples:

Code: Select all

#ifndef _MYHEADER
#define _MYHEADER
 
extern void __LIB__ myfunc(int a, int b);
extern void __LIB__ init(void);
 
#endif
I have tested without the __LIB__ qualifier, and it works perfectly, only linking the required ones. Later I added the __LIB__ to header file, but without recompiling the library, and the ZCC cannot find the symbols, after recompiling the library (the whole process, compiling with zcc then creating it with z88dk-z80asm) it does.
In both cases works fine, so not sure the purpose of the __LIB__ qualifier. I noticed that z88dk libraries uses it, so not sure if it is required for working correctly or is just because heritage from previous.
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

To be more precise, in both cases using or not using __LIB__ qualifer the binary is the same size, so probably the linker (that is z88dk-z80asm) already included in its linking process its new method to create libs.
But an official confirmation would be preferable, of course.
User avatar
jorgegv
Well known member
Posts: 287
Joined: Wed Nov 18, 2020 5:08 pm

Re: Creating library documentation needs an update

Post by jorgegv »

Try this code:

Code: Select all

// zcc +zx -vn -c test.c
// zcc +zx -vn -c -compiler=sdcc test.c
// Then check with: z88dk-z80nm test.o

int __LIB__ test_func_lib( void ) {
    return 3;
}

int test_func_nolib( void ) {
    return 3;
}
The __LIB__ qualifier only works with sccz80, and it makes it generate a stub linker symbol for the function, without the leading '_'. SDCC does not understand the __LIB__qualifier, and always generates all C symbols with leading '_', no matter they belong to a library or not.

You can remove the __LIB__ and try compiling with SDCC, you'll see.

I don't exactly see the point of all this dance, but surely some of the Z88DK eldest will have an answer :)
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Creating library documentation needs an update

Post by dom »

jorgegv wrote: Fri Jun 09, 2023 4:20 pmI don't exactly see the point of all this dance, but surely some of the Z88DK eldest will have an answer :)
I can't remember exactly why library routines couldn't start with an underscore, but with the z80asm from 25 years ago we had to explicitly indicate that routines came from a library hence the __LIB__ introduction.

It's been suggested that we get rid of it since it's not really needed anymore. However, it does still serve one useful purpose which is to distinguish between the entry points for variadic functions for the two compilers.
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

dom wrote: Fri Jun 09, 2023 4:42 pm It's been suggested that we get rid of it since it's not really needed anymore. However, it does still serve one useful purpose which is to distinguish between the entry points for variadic functions for the two compilers.
OK so for normal functions is not more required. About the 2nd sentence, not sure as not used yet in a case of library, but how it would work exactly? There is need to use the __LIB__ for library variadic functions in some way, and changes depending the compiler?. I got confused.
DarkSchneider
Member
Posts: 71
Joined: Sun Apr 01, 2018 4:02 pm

Re: Creating library documentation needs an update

Post by DarkSchneider »

Is there some way to do the library get a #define value at linking with no need to recompile it?
Probably not as it should be a binary for linking, but is worth to ask.

As solution I could create a script to recompile the libraries and getting the defined -DVALUE=xx in compilation sentence, but if it could get those defined values from the program compilation sentence would be great.
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Creating library documentation needs an update

Post by dom »

DarkSchneider wrote: Sat Jun 10, 2023 2:33 pm Is there some way to do the library get a #define value at linking with no need to recompile it?
Probably not as it should be a binary for linking, but is worth to ask.

As solution I could create a script to recompile the libraries and getting the defined -DVALUE=xx in compilation sentence, but if it could get those defined values from the program compilation sentence would be great.
I've not got a recipe from the top of my head, but classic does this sort of thing a lot. Some things to look at to see if they fit:

1. FOPEN_MAX/CLIB_FOPEN_MAX this defines the number of FILE * slots. It's configured at linktime and is exposed to library routines through a C header (for C files)
2. CLIB_32BIT_FLOATS, CLIB_64BIT_FLOATS - again configured at linktime and exposed to asm library routines using EXTERN CLIB_64BIT_FLOATS etc
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Creating library documentation needs an update

Post by dom »

DarkSchneider wrote: Fri Jun 09, 2023 4:56 pmOK so for normal functions is not more required. About the 2nd sentence, not sure as not used yet in a case of library, but how it would work exactly? There is need to use the __LIB__ for library variadic functions in some way, and changes depending the compiler?. I got confused.
Sorry, I missed this one. For sdcc variadic functions, arguments are pushed right -> left, and for sccz80 they're still pushed left->right so different treatment is needed. This is where the __LIB__ and the different entry points becomes useful.
Post Reply