Nick Cremelie wrote:
A clever idea! The problem is to get the parameters right. The above work for text files, but they're a bit unusual (and I wonder why GPC uses them for Input and Output).
So do I. But if I set them to e.g. 256,1 ("large" buffer, type text files), it didn't work. So I just took the values as for Input, Output).
The "buffer" is not a temporary buffer like in BP (if you know that), but Standard Pascal's file buffer. For text files, this must be a char, i.e. 1 byte, or 8 bits (where bits are indicated by the bit with value 2 in the flags), otherwise the routines won't work properly.
I'm not familiar with assembler listings, but I definitely see _p_initfdr somewhere in there. But don't forget that Input and Output are always initialized with that function.
That's different as their _p_initfdr calls are done from another RTS function, not from the program.
OK, I now have a suspicion what's wrong. I think both problems are related, and they're not really I/O problems, but due to the fact that the initialization code of the program is not executed.
Please try the following things:
- writeln (s.capacity), where s is a global string variable. If my theory is correct, it should write 0 or some nonsense value, instead of the correct capacity. That's why a wrong value will be passed to the read routine, and the varargs are not guilty.
- s.capacity := 255 (or whatever your capacity is) before the read. Then the read should work. This can serve as a workaround, just like the explicit InitFDR, until the real problem is found.
- Move all the code and (especially!) the variable declarations into a procedure. Then, both issues should be OK.
- Try a unit (or module) with initialization code, e.g. the following:
file foo.pas:
program foo; uses bar; begin end.
file bar.pas:
unit bar; interface implementation to begin do writeln('Hello, world'); end.
Then `gpc foo.pas bar.pas' or `gpc --automake foo.pas', and see if it writes anything.
- Try your test program (one with a global file variable) with RTS debugging. That's a little more complicated:
- change into p/rts and `make clean' - change back into the main (GCC) source directory and `make LANGUAGES="pascal" CFLAGS="-O2 -DDEBUG"' Perhaps you'll get an error about an undefined `_p_rts_version' in rts-rt0.c -- in this case replace this by `gpc_rts_version'. I hope you won't get any other errors. - install GPC - compile your program with the new GPC - run it with the command line options `-Grts -ddddd', and send me the output
Now for the reason why the initialization code of the program is not executed. I think I have got bad news:
As far as I understand the remarks in the GCC doc (see `info -f gcc -n Initialization'), this feature is not needed in C, and therefore has not been ported to all platforms. :-(
To confirm that, I checked config/rs6000/rs6000.h (which is included by the config/rs6000/aix*.h files), and it contains:
#define ASM_OUTPUT_CONSTRUCTOR(file, name) #define ASM_OUTPUT_DESTRUCTOR(file, name)
IOW, it just ignores the initialization and finalization code! Great, isn't it? :-(
So, what can be done:
- Implement this feature for your platform. But since you don't program in assembler, I don't suppose you know how to do this. I don't, either, but I suppose it's even more difficult than "ordinary" assembler programming...
- Find someone to implement it, perhaps in the GCC mailing lists or newsgroups. But seeing how much most C programmers "love" Pascal, I wish you best luck...
- Do it otherwise. Peter and I already discussed how to implement the initialization and finalization code with constructors and destructors. Actually, this was last week, and we were thinking about long-term ideas. We didn't expect it would come back to us so soon... Since most of this work would probably have to been done by Peter, I can't say how soon or late he can do this, but I fear, not so soon...
Here's another possible workaround:
Don't use units or modules with initializers or finalizers (if you need them, put the code into procedures, and call them manually).
For the program's initialization, insert the following into your program's declarations:
{ Dirty workaround for GCC bug } var p_collect_flag : asmname '_p_collect_flag' Integer; procedure program_initialize; asmname '__init_program_Foo';
where Foo is the name of your program with the first and only the first letter capitalized, no matter how you capitalized it in the "program foo;" declaration.
Immediately after the main "begin", add:
p_collect_flag := 0; program_initialize;
That's not very nice, I know, but it might work... To test it, try the following program. It should output 0 and 42.
program foo;
{ Dirty workaround for GCC bug } var p_collect_flag : asmname '_p_collect_flag' Integer; procedure program_initialize; asmname '__init_program_Foo';
var s : string (42);
begin { Simulate on my platform the missing initialization and test it } s.capacity := 0; writeln (s.capacity);
{ Now do the initialization manually } p_collect_flag := 0; program_initialize;
{ Test it } writeln (s.capacity); end.
The only thing I can do to simplify this is to let the RTS clear the p_collect_flag. That's what I did now, so with the next GPC version, it could work without the two lines referring to p_collect_flag.
Also, did you get any warnings (especially of type mismatches and the like) when compiling the RTS? This might indicate some non-portable type conversions in the C files.
These are all the warnings I got during the stage2 build for c and pascal using the stage 1 gcc-2.8.1 compiler (I didn't really worry about them, they did not seem too severe):
Most of the warnings are (a) known, (b) unrelated to the problem and (c) fixed in the next version. :-)
Frank
Hello all, hello Frank,
- writeln (s.capacity), where s is a global string variable. If my theory is correct, it should write 0 or some nonsense value, instead of the correct capacity. That's why a wrong value will be passed to the read routine, and the varargs are not guilty.
It's 0 indeed.
- s.capacity := 255 (or whatever your capacity is) before the read. Then the read should work. This can serve as a workaround, just like the explicit InitFDR, until the real problem is found.
This works all right.
- Move all the code and (especially!) the variable declarations into a procedure. Then, both issues should be OK.
This works fine.
Try a unit (or module) with initialization code, e.g. the following:
file foo.pas:
program foo; uses bar; begin end.
file bar.pas:
unit bar; interface implementation to begin do writeln('Hello, world'); end.
Then `gpc foo.pas bar.pas' or `gpc --automake foo.pas', and see if it writes anything.
It doesn't write anything...
- Try your test program (one with a global file variable) with RTS debugging. That's a little more complicated:
I'll check that out as soon as I have the time...
Now for the reason why the initialization code of the program is not executed. I think I have got bad news:
IOW, it just ignores the initialization and finalization code! Great, isn't it? :-(
Djeez, that's a nice feature!!!! Makes me think of M$ productes ;-)
So, what can be done:
- Implement this feature for your platform. But since you don't program in assembler, I don't suppose you know how to do this. I don't, either, but I suppose it's even more difficult than "ordinary" assembler programming...
I don't feel ready to do this...
- Find someone to implement it, perhaps in the GCC mailing lists or newsgroups. But seeing how much most C programmers "love" Pascal, I wish you best luck...
What's the address for the gcc mailing lists? If we present it as a "serious" bug in the rs6000 code, then maybe we can convince someone...
Here's another possible workaround:
Actually, workarounds are out of the question for us. We are testing the gpc compiler because we want to port our code written in xlp (IBM) pascal to different other platforms. From what we read in the documentation, gpc should be able to compile our xlp programs without many modifications (the only one we noticed so far is the interchange of %include (xlp) by #include (gpc). If we have to add all these workarounds, the project becomes, well, not viable. We want to port from AIX to Solaris, Linux and (yikes) NT.
Can't I hack something with the p_collect_flag and __init_program_xxx in the _p_run_constructors routine?
Nick