Re: Some doubt about participating in GCC community

2025-03-18 Thread Martin Jambor
Hi,

sorry, a word slipped from what I wanted to write:

On Mon, Mar 17 2025, Martin Jambor wrote:
> Hello,
>
> and sorry for a delayed reply.
>
> On Sat, Mar 08 2025, Gwen Fu wrote:
>> Good Afternoon Mr.Jambor!
>> Here are my questions:
>> 1.I am trying to do fix some easy bugs for participate in our community .
>> And a developer told me that I can  browse this web "
>> https://gcc.gnu.org/bugzilla/buglist.cgi?keywords=easyhack&list_id=113937&resolution=---";
>> .But most of these easyhacks are too old .   I don't know if these bugs
>> have been fixed or are unnecessary.
>
> Finding easy hacks in GCC is difficult.  That is why there are so few,
> they are outdated (though if any of the issues has been already solved,

I wanted to write that they are *often* outdated, not that they have
to be.  Many definitely aren't.

Sorry,

Martin


> the bug should have been closed).
>
> Sorry that I don't have a better answer.
>
>> 2.And if I want to take on the work of fixing these simple bugs, do I need
>> to send an email to the community?
>
> You don't have to.  Though writing a comment to the bug is usually
> beneficial and if you do decide to write an email, people may comment on
> your chosen strategy.
>
> Good luck!
>
> Martin


Re: Some doubt about participating in GCC community

2025-03-18 Thread Jonathan Wakely via Gcc
On Mon, 17 Mar 2025 at 22:46, Martin Jambor  wrote:
>
> Hello,
>
> and sorry for a delayed reply.
>
> On Sat, Mar 08 2025, Gwen Fu wrote:
> > Good Afternoon Mr.Jambor!
> > Here are my questions:
> > 1.I am trying to do fix some easy bugs for participate in our community .
> > And a developer told me that I can  browse this web "
> > https://gcc.gnu.org/bugzilla/buglist.cgi?keywords=easyhack&list_id=113937&resolution=---";
> > .But most of these easyhacks are too old .   I don't know if these bugs
> > have been fixed or are unnecessary.
>
> Finding easy hacks in GCC is difficult.  That is why there are so few,
> they are outdated (though if any of the issues has been already solved,
> the bug should have been closed).

Right, some of those easyhack bugs are old, but I don't know what "too
old" means.

If the bug has been fixed, it shouldn't still be open. You can always
check to see if the bug can still be reproduced with current GCC, and
if it can't, then adding a comment to the bug so it can be closed
would be very helpful.

The easyhack keyword exists for a reason, and is supposed to be useful
for precisely the purpose you're looking for. I'm not sure why you
would want to ignore it!


Re: bounds checking / VLA types

2025-03-18 Thread Martin Uecker via Gcc
Am Montag, dem 17.03.2025 um 16:45 -0700 schrieb Yeoul Na via Gcc:
> > 
> > > > On Mar 15, 2025, at 1:27 AM, Martin Uecker  wrote:

...

> > > > 
> > > > > > > > Anyway, a lot of this changes if we want to use the same 
> > > > > > > > concept for
> > > > > > > > non-local pointers to arrays, because we no longer have an 
> > > > > > > > obvious point of
> > > > > > > > execution at which to evaluate the bounds expression. Instead, 
> > > > > > > > we are forced
> > > > > > > > into re-evaluating it every time we access the variable holding 
> > > > > > > > the array.
> > > > > > > > Consider:
> > > > > > > > struct X { int count; int (*ptr)[count * 10]; // using my 
> > > > > > > > preferred syntax }; void test(struct X *xp) { // For the 
> > > > > > > > purposes of the conversion check here, the // source type is
> > > > > > > > int (*)[<
> > > > > > > > xp->count * 10 >], freshly // evaluated as part of the member 
> > > > > > > > access. int (*local)[100] = xp->ptr; }
> > > > 
> > > > Yes, except for the syntax, this is how we plan to do it.
> > 
> > That would be great, but I’m curious how VLA types can be evolved
> > to support this safely without making it inconsistent with how local
> > pointers to arrays are currently handled.
> > Are you imagining something like below where the VLA types work
> > differently depending on the declaration the types are applied to?
> > Or you meant consistently fixing how the existing VLA types work?

The time of point where the size expression is evaluated needs
to be specified. For a size expression that contains .n this
can only need to be the time when the structure member of VM 
type is accessed.

> > 
> > 
> > struct X {
> > int count;
> > int (*ptr)[count];
> > };
> > 
> > void test(struct X *xp) {
> > int len = 10;
> > int (*ptr)[len] = malloc(sizeof(int) * len);
> > 
> > xp->count = 100; // does dynamically change the type of xp->ptr.
> > xp->ptr = malloc(sizeof(int) * 100); // hence, this works fine.

This yet has to be decided, but the following is a way
how this could be done.

When xp->ptr is accessed, the size expression
is evaluated and the lvalue which is formed at this point in
time gets the type int(*)[xp->count], similar to how the size
expression of function arguments are evaluated when the
function is entered. The type of this expression
then does not change anymore. You could implement it
by rewriting it to the following.

struct X {
 int count;
 int (*ptr)[];
};

#define ACCESS(xp) *( (int(**)[(xp)->count]) &(xp)->ptr)

xp->count = 100;
ACCESS(xp) = malloc(sizeof(int) * 100);

https://godbolt.org/z/r9WTb86xM

So this could be implemented in the compiler front-end
as builds on top of the existing framework for
variably-modified types.


To make it safe we would need to also enforce some additional
rules, e.g. that you have to (re-)assign the pointer after
setting the count. This could be implemented by adding new
warnings.

Martin



> > 
> > len = 5; // does not change the type of ptr.
> > ptr = malloc(sizeof(int) * len); // hence, this traps at run time. 
> > }
> > 


> > 
> > > > 
> > > > Based on my experience with other languages, I also think it is
> > > > useful to be able to refer to bounds outside of the struct
> > > > definition, e.g.
> > > > 
> > > > int foo(int n, struct foo { char (*ptr)[n]; } x);
> > > > 
> > > > struct foo { char (*ptr)[10]; } x = ...;
> > > > foo(10, x);
> > > > 
> > > > which GCC happens to support already:
> > > > 
> > > > https://godbolt.org/z/ja7qvMqPE
> > > > 
> > > > 
> > > > This becomes useful if you want to be able to express the
> > > > relation of different types, e.g. that two data structures
> > > > used as input for something point to buffers of the same length.
> > > > 
> > > > But the dependent sum type that we still miss is definitely
> > > > more important.
> > > > 
> > > > > > > > This has several immediate consequences.
> > > > > > > > Firstly, we need to already be able to compute the correct 
> > > > > > > > bound when we do
> > > > > > > > the dynamic checks for assignments into this field. For local 
> > > > > > > > variably-
> > > > > > > > modified types, everything in the expression was already in 
> > > > > > > > scope and
> > > > > > > > presumably initialized, so this wasn’t a problem. Here, we’re 
> > > > > > > > not helped
> > > > > > > > by scope, and we are dependent on the count field already 
> > > > > > > > having been
> > > > > > > > initialized.
> > > > > > > > Secondly, we must be very concerned about anything that could 
> > > > > > > > change the
> > > > > > > > result of this evaluation. So we cannot allow an arbitrary 
> > > > > > > > expression;
> > > > > > > > it must be something that we can fully analyze for what could 
> > > > > > > > change it.
> > > > > > > > And if refers to variables or fields (which it presumably 
> > > > > > > > always will), we
> > > > > > > > must prevent assignments to those, or at least validate that any
>

Re: bounds checking / VLA types

2025-03-18 Thread Martin Uecker via Gcc
Am Dienstag, dem 18.03.2025 um 14:03 -0700 schrieb Yeoul Na via Gcc:
> 
> > On Mar 18, 2025, at 12:48 PM, Martin Uecker  wrote:
> > 
> > Am Dienstag, dem 18.03.2025 um 09:52 -0700 schrieb Yeoul Na via Gcc:
> > > 
> > > > On Mar 18, 2025, at 12:16 AM, Martin Uecker  wrote:
> > > > 
> > > > When xp->ptr is accessed, the size expression
> > > > is evaluated and the lvalue which is formed at this point in
> > > > time gets the type int(*)[xp->count], similar to how the size
> > > > expression of function arguments are evaluated when the
> > > > function is entered. The type of this expression
> > > > then does not change anymore. You could implement it
> > > > by rewriting it to the following.
> > > 
> > > Yes, that’s effectively similar to how the size of bounds annotations 
> > > work too.
> > > 
> > > Though my question was, VLA types currently don't work this way.
> > > 
> > > The size is evaluated when it’s declared as you all discussed earlier.
> > 
> > this is the case only for automatic variables.  For function arguments
> > they are evaluated at function entry.
> 
> Well, I think saying this way sounds a bit misleading. This works this
> way because function parameters are automatic variables of the function
> and their declarations are reached at the entry of the function.

There is no control flow which goes through the declarations
of the arguments in the function prototype, which would define
exactly when in what order these "declarations are reached",
while this is clear for function-scope declarations which
are actually reached by control flow.

The C standard just explicitely states that on function
entry those size expressions are evaluated.

> And by “only for automatic variables’, then you mean global
> and static variables are not or won't be working in the same
> way as the automatic variables in the future? 

I should have said objects defined at function-scope.
static variables already work like this. 

> For global and static variables, I meant “pointers" to VLA types.
> 
> Also, what about a pointer to pointer to an array? Should it
> be fixed to be evaluated at the time of use?

According to the C standard, the size expression
for the example below is evaluated on function entry.

We try to not break existing code in C without a very
good reason, so I do not think this can be changed
(but it also seems just fine to me how it is).

> 
> int foo(int len, int (*((*inout_buf)[len])) {
>   // use *inout_buf 
>   // ...
> 
>   int new_len = 10;
>   *out_buf = malloc(new_len); // should it be fixed to be evaluated at the 
> time of use?
> 
>   return new_len; 
> } 
> 
> 
> > 
> > > So do you mean you want to fix the current behavior or make the
> > 
> > I think the current behavior is fine, and changing it
> > would also be problematic for existing code.
> > 
> > > behavior inconsistent between if they are struct members,
> > > indirect pointers vs. local variables like below? 
> > 
> > I think the nature of the problem requires that the size
> > expression must be evaluated at different time points
> > depending on the scenario.
> > 
> > For automatic variables, this is when the declaration is
> > reached in the control flow and for function arguments when
> > the function is entered.  For structure members where the size
> > expression refers to other members, they need to be
> > evaluated when the member is accessed. 
> > 
> > > 
> > > void test(struct X *xp) {
> > >int len = 10;
> > >int (*ptr)[len] = malloc(sizeof(int) * len); // (1) int (*ptr)[len] is 
> > > evaluated here and fixed.  
> > > 
> > >xp->count = 100;
> > >xp->ptr = malloc(sizeof(int) * 100); // size of xp->ptr is dynamically 
> > > evaluated with xp->count, hence, this works fine.
> > > 
> > >len = 5; // (2)
> > >ptr = malloc(sizeof(int) * len); // size of ptr is still fixed to be 
> > > (1), so this traps at run time. 
> > > }
> > 
> > Yes.
> 
> I think the fact that the behavior diverges in this subtle
> way will make things very confusing. 
> 
I use it in this way (using a macro for access) and think 
it works very nicely.

> Not sure adding “dot” actually helps that much with the users
> comprehending this code. 
> 
Based on my humble experience, I would say that it helps people
to avoid mistakes when things that do behave differently do not
look identically.

> That’s why I was quite skeptical if VLA in C can ever be evolved
> to model the size with a struct member safely, given that VLA made
> a wrong choice from the beginning.

I don't think a wrong choice was made. 

The alternative would be to have the type of a variable
change whenever a variable in the size expression changes.
I think this would be much harder to understand and cause
more errors.

For a structure members there is no alternative.  But it is 
also less problematic than for other variables, because we
need to restrict the expressions which we allow in this 
context anyhow.  I also like things to be consistent, but
different

Re: Remove duplication for the handling of attributes between different frontends

2025-03-18 Thread Richard Biener via Gcc
On Tue, Mar 18, 2025 at 4:49 PM Antoni Boucher via Gcc  wrote:
>
> Hi.
> We're trying to remove the duplication of the attributes code between
> the C and libgccjit frontend.
> The attached patch shows a draft of this attempt that only supports a
> few attributes.
> Would that kind of approach be acceptable (I'm not sure since this
> includes a c-family file in libgccjit)?
> If not, do you have any idea of how we could do this?

I would suggest to try moving to the middle-end and possibly amend the
attribute table maintained there by an extra field with a bitfield of languages
the attribute should be implemented for (or just move those that should
be available everywhere).  The LTO "frontend" is another place where we
have duplicates (and you could say the LTO "frontend" is really the middle-end
variant).

Richard.

> Thanks.


Proposed GSoC project to enhance the GCC GNAT Ada front end

2025-03-18 Thread Tucker Taft via Gcc
Proposal: Google Summer of Code on GCC Ada Front end

   -

   Goal : Implement some of the light-weight parallelism features of Ada
   2022 in the GNAT front end
   -

   Contributor: Ethan Luis McDonough, PSU '2025 (
   ethanluismcdono...@gmail.com)
   -

   Mentors: S. Tucker Taft (Lexington, MA -- tucker.t...@gmail.com) and
   Richard Wai (Toronto, ON -- rich...@annexi-strayline.com)

The GNAT front end does not currently recognize the "parallel" keyword
added as part of Ada 2022.  The goal of this project is to add support in
the GNAT parser for the two most important places where the "parallel"
keyword is used, namely the parallel "for" loop, and the parallel "do"
statement.

Here is the Ada 2022 syntax for the parallel parts of the "for" loop (from
https://adaic.org/resources/add_content/standards/22rm/html/RM-5-5.html):

loop_statement ::=

   [loop_statement_identifier

:]

  [iteration_scheme
]
loop

 sequence_of_statements


   end loop [loop_identifier

];

iteration_scheme ::= ...

   | [parallel [aspect_specification

]]

 for procedural_iterator


   | parallel [(chunk_specification
)]
[aspect_specification

]

 for loop_parameter_specification


   | parallel [(chunk_specification
)]
[aspect_specification

]

 for iterator_specification


chunk_specification ::=

 integer_simple_expression


   | defining_identifier

in discrete_subtype_definition


loop_parameter_specification ::=

   defining_identifier

in [reverse] discrete_subtype_definition


 [iterator_filter

]

iterator_filter ::= when condition


Here is the Ada 2022 syntax for the parallel "do" statement (from
https://adaic.org/resources/add_content/standards/22rm/html/RM-5-6-1.html):

parallel_block_statement ::=

parallel [(chunk_specification
)]
[aspect_specification
]
do

   sequence_of_statements


and

   sequence_of_statements


   {and

   sequence_of_statements

}

end do;

The chunk_specification
,
if any, of a parallel_block_statement

shall be an integer_simple_expression

.

The GNAT front end is organized into three basic phases, a parser, a
semantic analyzer, and an expander.  In the sources, these are represented
by source files par-ch*.adb, sem_ch*.{ads,adb}, and exp_ch*.{ads,adb},
where "ch*" is short-hand for the various chapters of the Ada reference
manual.  For this project the intent is to augment primarily the "chapter
5" components, given that loop and parallel-do statements are defined in
chapter 5 of the Ada reference manual.  For example, the function
Par.Ch5.P_Loop_Statement is where most of the parsing of the loop statement
takes place, while Par.Ch5.P_Parallel_Do_Statement would be a new local
function of Par.Ch5.  Similarly

Re: bounds checking / VLA types

2025-03-18 Thread Yeoul Na via Gcc



> On Mar 18, 2025, at 12:48 PM, Martin Uecker  wrote:
> 
> Am Dienstag, dem 18.03.2025 um 09:52 -0700 schrieb Yeoul Na via Gcc:
>> 
>>> On Mar 18, 2025, at 12:16 AM, Martin Uecker  wrote:
>>> 
>>> When xp->ptr is accessed, the size expression
>>> is evaluated and the lvalue which is formed at this point in
>>> time gets the type int(*)[xp->count], similar to how the size
>>> expression of function arguments are evaluated when the
>>> function is entered. The type of this expression
>>> then does not change anymore. You could implement it
>>> by rewriting it to the following.
>> 
>> Yes, that’s effectively similar to how the size of bounds annotations work 
>> too.
>> 
>> Though my question was, VLA types currently don't work this way.
>> 
>> The size is evaluated when it’s declared as you all discussed earlier.
> 
> this is the case only for automatic variables.  For function arguments
> they are evaluated at function entry.

Well, I think saying this way sounds a bit misleading. This works this way 
because function parameters are automatic variables of the function and their 
declarations are reached at the entry of the function.
And by “only for automatic variables’, then you mean global and static 
variables are not or won't be working in the same way as the automatic 
variables in the future? For global and static variables, I meant “pointers" to 
VLA types.

Also, what about a pointer to pointer to an array? Should it be fixed to be 
evaluated at the time of use?

int foo(int len, int (*((*inout_buf)[len])) {
  // use *inout_buf 
  // ...

  int new_len = 10;
  *out_buf = malloc(new_len); // should it be fixed to be evaluated at the time 
of use?

  return new_len; 
} 


> 
>> So do you mean you want to fix the current behavior or make the
> 
> I think the current behavior is fine, and changing it
> would also be problematic for existing code.
> 
>> behavior inconsistent between if they are struct members,
>> indirect pointers vs. local variables like below? 
> 
> I think the nature of the problem requires that the size
> expression must be evaluated at different time points
> depending on the scenario.
> 
> For automatic variables, this is when the declaration is
> reached in the control flow and for function arguments when
> the function is entered.  For structure members where the size
> expression refers to other members, they need to be
> evaluated when the member is accessed. 
> 
>> 
>> void test(struct X *xp) {
>>int len = 10;
>>int (*ptr)[len] = malloc(sizeof(int) * len); // (1) int (*ptr)[len] is 
>> evaluated here and fixed.  
>> 
>>xp->count = 100;
>>xp->ptr = malloc(sizeof(int) * 100); // size of xp->ptr is dynamically 
>> evaluated with xp->count, hence, this works fine.
>> 
>>len = 5; // (2)
>>ptr = malloc(sizeof(int) * len); // size of ptr is still fixed to be (1), 
>> so this traps at run time. 
>> }
> 
> Yes.

I think the fact that the behavior diverges in this subtle way will make things 
very confusing. Not sure adding “dot” actually helps that much with the users 
comprehending this code. That’s why I was quite skeptical if VLA in C can ever 
be evolved to model the size with a struct member safely, given that VLA made a 
wrong choice from the beginning. That said this is just my own impression and 
whether we can make the usable model this way may need more study.

At least now I understand what is your vision. Thanks.

> 
> For GNU C (but not ISO C) there could be size expression in
> the declaration referring to automatic variables.
> 
> int foo()
> {
>  int n = 1;
>  struct {
>   char buf[n]; // evaluated when the declaration is reached
>  } x;
> };
> 
> This is something which can not currently happen for ISO C where
> this can only refer to named constants and where the size is
> evaluated at compile time.
> 
> int foo()
> {
>  enum { N = 1 };
>  struct {
>char buf[N];
>  } x;
> }
> 
> Still, I think this is another reason why it would be much
> better to have new syntax for this.  We also need to restrict
> the size expressions in all three scenarios in different ways.
> 
> int foo()
> { 
>  int n = 1;
>  struct {
> 
>int m;
>char buf1[n];  // evaluated when the declaration is reached
>char buf2[.m]; // evaluated on access to buf2, restricted syntax
>  } x { .m = 10 };
> }
> 
> 
> Martin

Yeoul



Re: bounds checking / VLA types

2025-03-18 Thread Martin Uecker via Gcc
Am Dienstag, dem 18.03.2025 um 09:52 -0700 schrieb Yeoul Na via Gcc:
> 
> > On Mar 18, 2025, at 12:16 AM, Martin Uecker  wrote:
> > 
> > When xp->ptr is accessed, the size expression
> > is evaluated and the lvalue which is formed at this point in
> > time gets the type int(*)[xp->count], similar to how the size
> > expression of function arguments are evaluated when the
> > function is entered. The type of this expression
> > then does not change anymore. You could implement it
> > by rewriting it to the following.
> 
> Yes, that’s effectively similar to how the size of bounds annotations work 
> too.
> 
> Though my question was, VLA types currently don't work this way.
> 
> The size is evaluated when it’s declared as you all discussed earlier.

this is the case only for automatic variables.  For function arguments
they are evaluated at function entry.

> So do you mean you want to fix the current behavior or make the

I think the current behavior is fine, and changing it
would also be problematic for existing code.

> behavior inconsistent between if they are struct members,
> indirect pointers vs. local variables like below? 

I think the nature of the problem requires that the size
expression must be evaluated at different time points
depending on the scenario.

For automatic variables, this is when the declaration is
reached in the control flow and for function arguments when
the function is entered.  For structure members where the size
expression refers to other members, they need to be
evaluated when the member is accessed. 

> 
> void test(struct X *xp) {
> int len = 10;
> int (*ptr)[len] = malloc(sizeof(int) * len); // (1) int (*ptr)[len] is 
> evaluated here and fixed.  
> 
> xp->count = 100;
> xp->ptr = malloc(sizeof(int) * 100); // size of xp->ptr is dynamically 
> evaluated with xp->count, hence, this works fine.
> 
> len = 5; // (2)
> ptr = malloc(sizeof(int) * len); // size of ptr is still fixed to be (1), 
> so this traps at run time. 
> }

Yes.

For GNU C (but not ISO C) there could be size expression in
the declaration referring to automatic variables.

int foo()
{
  int n = 1;
  struct {
   char buf[n]; // evaluated when the declaration is reached
  } x;
};

This is something which can not currently happen for ISO C where
this can only refer to named constants and where the size is
evaluated at compile time.

int foo()
{
  enum { N = 1 };
  struct {
char buf[N];
  } x;
}

Still, I think this is another reason why it would be much
better to have new syntax for this.  We also need to restrict
the size expressions in all three scenarios in different ways.

int foo()
{ 
  int n = 1;
  struct {

int m;
char buf1[n];   // evaluated when the declaration is reached
char buf2[.m];  // evaluated on access to buf2, restricted syntax
  } x { .m = 10 };
}


Martin





Re: bounds checking / VLA types

2025-03-18 Thread Yeoul Na via Gcc



> On Mar 18, 2025, at 12:16 AM, Martin Uecker  wrote:
> 
> When xp->ptr is accessed, the size expression
> is evaluated and the lvalue which is formed at this point in
> time gets the type int(*)[xp->count], similar to how the size
> expression of function arguments are evaluated when the
> function is entered. The type of this expression
> then does not change anymore. You could implement it
> by rewriting it to the following.

Yes, that’s effectively similar to how the size of bounds annotations work too.

Though my question was, VLA types currently don't work this way. The size is 
evaluated when it’s declared as you all discussed earlier. So do you mean you 
want to fix the current behavior or make the behavior inconsistent between if 
they are struct members, indirect pointers vs. local variables like below? 

void test(struct X *xp) {
int len = 10;
int (*ptr)[len] = malloc(sizeof(int) * len); // (1) int (*ptr)[len] is 
evaluated here and fixed.  

xp->count = 100;
xp->ptr = malloc(sizeof(int) * 100); // size of xp->ptr is dynamically 
evaluated with xp->count, hence, this works fine.

len = 5; // (2)
ptr = malloc(sizeof(int) * len); // size of ptr is still fixed to be (1), 
so this traps at run time. 
}

Yeoul

i386 EBCDIC

2025-03-18 Thread Paul Edwards via Gcc
Hi.

I already have a mini-clone of Windows (two actually -
PDOS/386 and PDOS-generic), but both are ASCII.

I now wish to create an EBCDIC version.

I have an i370 EBCDIC version already (z/PDOS and
z/PDOS-generic), and the end result is that I have been
able to compile the gcc 3.2.3 source code on z/PDOS-generic
targeting i386 EBCDIC.

Dave Pitts has already made the modifications suitable
for gccmvs (i370) to run, but gccwin (i386) is giving this error:

enter a command
type test.c
int main(void)
{
printf("hello, world\n");
return 5;
}

enter a command
gccwin -S -Os test.c
about to call app at address 003F74B8
test.c: In function `main':
test.c:5: Internal compiler error in schedule_block, at :1659
Please submit a full bug report,
with preprocessed source if appropriate.
See http://gcc.gnu.org/bugs.html> for instructions.
return from app is hex 1

enter a command


I don't have this issue on an ASCII machine, but it
generates incorrect assembler (EBCDIC codes
converted to ASCII) - a problem that can be bypassed
by starting with EBCDIC source code (which I did,
above). Even in steady state (working on EBCDIC
mini-Windows-clone), I will need this problem solved.

Switching off optimization works:

enter a command
gccwin -S -O0 test.c
about to call app at address 003F74B8
return from app is hex 0

enter a command
type test.s
 .file "test.c"
 .text
LC0:
 .ascii "hello, world\25\0"
.globl _main
_main:
 pushl %ebp
 movl %esp, %ebp
 subl $8, %esp
 andl $-16, %esp
 movl $0, %eax
 subl %eax, %esp
 subl $12, %esp
 pushl $LC0
 call _printf
 addl $16, %esp
 movl $5, %eax
 leave
 ret

enter a command


The modified gcc 3.2.3 source code is in gcc-stage* in
custom.zip at http://pdos.org

The problem is almost certainly some issue arising from
gcc source code making some ASCII assumption. That
hasn't already been found and addressed by Dave Pitts.

Any suggestions on where the problem may lie?

(and yes, I realize that gcc 3.2.3 isn't officially supported -
there are reasons I am still on this version - one being
the i370 target which I have just used).

Thanks. Paul.