Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2012-11

array of const with cdecl procedure

12 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

ik

Hello,

I'm trying to write a shard library of my own that you can use with C as well. I'm using mode fpc, and not objfpc.

I created something like this:

...
procedure varargs_example(params : array of consts); cdecl; ...

The compiler report an error:
Error:Type identifier expected
Fatal: Syntax error, ")" expected but "CONST" found

Please note that I need to access the "params" variable inside my code. How can I implement it correctly with FPC 2.6.0 ?

Thanks,
Ido

Sven Barth
to ik
ik wrote 18 lines
Hello, I'm trying to write a shard library of my own that you can use with C as well. I'm using mode fpc, and not objfpc. I created something like this: ... procedure varargs_example(params : array of consts); cdecl; ... The compiler report an error: Error:Type identifier expected Fatal: Syntax error, ")" expected but "CONST" found Please note that I need to access the "params" variable inside my code. How can I implement it correctly with FPC 2.6.0 ?

You can not write cdecl functions with variable argument lists in FPC. You can only access such functions exported from C code. See also here: http://wiki.freepascal.org/User_Changes_2.6.0#Array_of_const_parameters_and_cdecl_routines

Regards,
Sven

ik
to Sven Barth
Sven Barth wrote 25 lines
On 11.11.2012 13:40, ik wrote: > > Hello, > > I'm trying to write a shard library of my own that you can use with C > as well. I'm using mode fpc, and not objfpc. > > I created something like this: > > ... > procedure varargs_example(params : array of consts); cdecl; > ... > > The compiler report an error: > Error:Type identifier expected > Fatal: Syntax error, ")" expected but "CONST" found > > > Please note that I need to access the "params" variable inside my code. > How can I implement it correctly with FPC 2.6.0 ? You can not write cdecl functions with variable argument lists in FPC. You can only access such functions exported from C code. See also here: http://wiki.freepascal.org/User_Changes_2.6.0#Array_of_const_parameters_and_cdecl_routines

I know this one, but here I'm the one who write the code that is exported to C and not vice versa.
How can I write it in a way that C can also use it ?

Show quoted text 6 lines
Regards, Sven _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Sven Barth
to ik
ik wrote 30 lines
On Sun, Nov 11, 2012 at 2:54 PM, Sven Barth wrote: > On 11.11.2012 13:40, ik wrote: >> >> Hello, >> >> I'm trying to write a shard library of my own that you can use with C >> as well. I'm using mode fpc, and not objfpc. >> >> I created something like this: >> >> ... >> procedure varargs_example(params : array of consts); cdecl; >> ... >> >> The compiler report an error: >> Error:Type identifier expected >> Fatal: Syntax error, ")" expected but "CONST" found >> >> >> Please note that I need to access the "params" variable inside my code. >> How can I implement it correctly with FPC 2.6.0 ? > > > You can not write cdecl functions with variable argument lists in FPC. You > can only access such functions exported from C code. See also here: > http://wiki.freepascal.org/User_Changes_2.6.0#Array_of_const_parameters_and_cdecl_routines I know this one, but here I'm the one who write the code that is exported to C and not vice versa. How can I write it in a way that C can also use it ?

Yes and this is exactly what the change states. You can not write "varargs" functions in Pascal that can be accessed from C.

The only solution would be to basically do something like the TVarRec record does: have a record of which one field is a "type specifier" and the remaining is a union out of the different supported types. You then pass a Pointer to the first element of an array of that type and the length of the array to the Pascal function. The negative point is of course that you'll need to instantiate, populate and afterwards free the array you pass to the pascal function.

Regards,
Sven

Bernd
to Sven Barth

2012/11/11 Sven Barth :

Yes and this is exactly what the change states. You can not write "varargs" functions in Pascal that can be accessed from C.

Wouldn't it be possible to write a function in pascal that declares a simple longint parameter instead of the varargs and then inside the function use the stack pointer (the address of that argument) to read the entire list from the stack directly? Since in cdecl the caller will clean up the stack after the function call this should not cause any problems?

something along these lines (for example if a list of longints should be passed):

procedure FakeVararg(dummy: LongInt);
var
  Start: PLongInt;
  First, Second, Third: LongInt;
begin
  Start := PLongInt(@dummy);
  First := Start[0];
  Second := Start[1];
  Third := Start[2];
end;

(or something very similar to this, not sure if the above code works already, not tested)

Jonas Maebe
to Bernd
Bernd wrote
Wouldn't it be possible to write a function in pascal that declares a simple longint parameter instead of the varargs and then inside the function use the stack pointer (the address of that argument) to read the entire list from the stack directly?

No, because the C varargs calling convention does not simply pass the parameters on the stack on most platforms.

Jonas

Bernd
to Jonas Maebe

2012/11/11 Jonas Maebe :

No, because the C varargs calling convention does not simply pass the parameters on the stack on most platforms.

Where else are the arguments if not on the stack? Everything I have read so far about varargs and cdecl says they are on the stack.

Jonas Maebe
to Bernd
Bernd wrote 5 lines
2012/11/11 Jonas Maebe : > No, because the C varargs calling convention does not simply pass the parameters on the stack on most platforms. Where else are the arguments if not on the stack?

In registers.

Everything I have read so far about varargs and cdecl says they are on the stack.

Then you probably only read about i386 ABIs (and maybe m68k).

Jonas

Bernd
to Jonas Maebe

2012/11/11 Jonas Maebe :

Then you probably only read about i386 ABIs (and maybe m68k).

But a bunch of ifdefs should do the trick then, it should still be possible to implement every possible implementation in pascal somehow.

Is there a document somewhere that specifies how exactly cdecl varargs is implemented on the different platforms? I could no find anything. Since fpc can *call* vararg functions the knowledge about how exactly they are implemented on all the different platforms must exist somewhere?

Jonas Maebe
to Bernd
Bernd wrote 6 lines
2012/11/11 Jonas Maebe : > Then you probably only read about i386 ABIs (and maybe m68k). But a bunch of ifdefs should do the trick then, it should still be possible to implement every possible implementation in pascal somehow.

No, it is not possible. There are no Pascal (or C, for that matter) expressions that map to particular registers on entry into the function.

Is there a document somewhere that specifies how exactly cdecl varargs is implemented on the different platforms?

There is one such document per ABI. These individual ABI documents are located all over the web. E.g. the official x86-64 ABI can be found at http://www.x86-64.org/documentation/abi.pdf, while the one for Win64 can be found at http://msdn.microsoft.com/en-us/library/ms235286.aspx

I could no find anything. Since fpc can *call* vararg functions the knowledge about how exactly they are implemented on all the different platforms must exist somewhere?

It's much easier to construct it on the caller side than on the callee side. On the caller side, the information can be statically determined at compile time based on the types and order of the passed parameters. On the callee side, the information has to be dynamically determined. Moreover, the location of a cdecl varargs parameter generally depends on the number *and* types of the previous varargs parameters, so an expressions such as params[i] or even params[1] could never be supported. That's why in C you also have to use the va_start/va_arg/va_copy/va_end intrinsics to sequentially walk all such parameters.

Jonas

Mark Morgan Lloyd
to Jonas Maebe
Jonas Maebe wrote
> Is there a document somewhere that specifies how exactly cdecl varargs > is implemented on the different platforms? There is one such document per ABI. These individual ABI documents are located all over the web. E.g. the official x86-64 ABI can be found at http://www.x86-64.org/documentation/abi.pdf, while the one for Win64 can be found at http://msdn.microsoft.com/en-us/library/ms235286.aspx

I started trying to make a list of resources at
http://wiki.lazarus.freepascal.org/Assembler_and_ABI_Resources but it's still largely just placeholders.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]
Bernd
to Jonas Maebe: No, it is not possible. There are no Pascal (or C, for that matter) expressions that map…

2012/11/11 Jonas Maebe :

No, it is not possible. There are no Pascal (or C, for that matter) expressions that map to particular registers on entry into the function.

ok, my wording was wrong. What I really meant to say was that if I am absolutely determined to find a solution because I have no influence on the calling side then it would still be possible to implement such a function using only the means that are available in fpc. When I said "is possible in Pascal" I really wanted to say "is possible with fpc alone without having to make a separate C wrapper, even if it becomes ridiculously complicated". Because "impossible" is such an absolute word and used much too often I usually tend to not accept it without proof.

I could for example make it an asm procedure (with separate implementation for each architecture) that first takes the fixed arguments and then pushes all remaining argument registers (if any) to the stack and then calls a pascal procedure (the same for all architectures) with the fixed arguments and a pointer to the register save area and the number of saved registers and another pointer to the stack area where to continue looking for more arguments should the registers be exhausted. And the next step (if needed more than once) would be to try to factor out most (or all?) of this into some easily callable/includable code that resembles the functionality of the va_start, va_arg and va_end macros and hides all the ifdef ugliness.