Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

vsprintf() unter Linux und Strong ARM

8 views
Skip to first unread message

Hans Bonfigt

unread,
Jul 18, 2002, 3:59:05 PM7/18/02
to
Guten Abend !


Folgendes Programm laeuft nicht mit libc6 / gcc 2.5.3 fuer Strong ARM:


Es ist ein altes Beispiel aus den spaeten 80ern, daher noch kein
Prototyping.


[ ... ]

void errmsg(); /* Fehlermeldungen ausgeben */


[ ... ]

if (flg<0) { /* Radikand o.K. ? */
errmsg("Erkenne %s nicht als Zahl, Abbruch !",*(argv+1));
exit (ENUMB);
}

[ ... ]


/* VARARGS1 */
void errmsg(fmt)
char* fmt;
{
typedef va_list vptype;

vptype adr;
char str[320+1];
int l;

adr=(vptype)&fmt+sizeof(fmt);

l=sprintf(str,"%s: ",prcn);
(void)vsprintf(str+l,fmt,adr);
(void)fprintf(stderr,"%s\n",str);
}


Ergebnis: Der 'vsprintf' verursacht entweder Segfaults oder SIGBUS,
je nachdem, ob mit '-O3' compiliert wurde oder nicht.

Das Programm laeuft unter verschiedenen Unix-Dialekten und auch
unter x86-Linux, nur halt nicht auf der ARM-Plattform.

Gibt es Besonderheiten bei der Parameteruebergabe ?


Gruss,

--
Hans Bonfigt /SES/
UNIX App. Development Systementwicklung Schollmeier
Phone: +49 171 3758928 <bonfigt....@t-online.de>

Falk Hueffner

unread,
Jul 18, 2002, 7:01:48 PM7/18/02
to
Hans Bonfigt <bonfigt....@t-online.de> writes:

> /* VARARGS1 */
> void errmsg(fmt)
> char* fmt;
> {
> typedef va_list vptype;
>
> vptype adr;
> char str[320+1];
> int l;
>
> adr=(vptype)&fmt+sizeof(fmt);

Hier solltest du va_start nehmen; die Argumente muessen nicht
unbedingt im Speicher liegen (in der Tat tun sie das bei den wenigsten
Architekturen).

> l=sprintf(str,"%s: ",prcn);
> (void)vsprintf(str+l,fmt,adr);
> (void)fprintf(stderr,"%s\n",str);
> }


--
Falk

Wolfgang Denk

unread,
Jul 18, 2002, 8:08:57 PM7/18/02
to
Hans Bonfigt <bonfigt....@t-online.de> writes:

>/* VARARGS1 */
>void errmsg(fmt)
> char* fmt;
>{
> typedef va_list vptype;

> vptype adr;
> char str[320+1];
> int l;

> adr=(vptype)&fmt+sizeof(fmt);

> l=sprintf(str,"%s: ",prcn);
> (void)vsprintf(str+l,fmt,adr);
> (void)fprintf(stderr,"%s\n",str);

Grrrrgh.... vielleicht solltest Du doch mal nachlesen, wie Funktionen
mit variabler Argumentanzahl zu implementieren sind.

>Ergebnis: Der 'vsprintf' verursacht entweder Segfaults oder SIGBUS,
>je nachdem, ob mit '-O3' compiliert wurde oder nicht.

Jau, das geschieht dir recht, würde ich sagen: Undefined Behaviour.

>Gibt es Besonderheiten bei der Parameteruebergabe ?

Niemand garantiert Dir, daß du die Adresse irgendwelchger Argumente
so bzw. überhaupt berechnen kannst; oft haben die gar keine Adresse
(sondern werden in Registern übergeben).


Der Code ist so hochgradig unportabel daß es sich gar nicht lohnt,
darüber zu diskutieren.

Mein Rat: "man stdarg".

Wolfgang Denk

--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-4596-87 Fax: (+49)-8142-4596-88 Web: www.denx.de
Whom the gods would destroy, they first teach BASIC.

Hans Bonfigt

unread,
Jul 19, 2002, 7:12:34 AM7/19/02
to
Wolfgang Denk:

>
> Grrrrgh.... vielleicht solltest Du doch mal nachlesen, wie Funktionen
> mit variabler Argumentanzahl zu implementieren sind.

Wenn ich das taete, stiesse ich auf 'stdarg.h'.

Die Verwendung von 'va_start()' im Zusammenhang mit 'stdarg.h' wiederum
erzwingt unter gcc die Verwendung einer Ellipsis, anderenfalls das
schlaue Kerlchen meckert. Vulgo: Dann muesste den ganzen Mist doch
noch auf ANSI-C umstellen.


> >Gibt es Besonderheiten bei der Parameteruebergabe ?
>
> Niemand garantiert Dir, daß du die Adresse irgendwelchger Argumente
> so bzw. überhaupt berechnen kannst; oft haben die gar keine Adresse
> (sondern werden in Registern übergeben).

Nicht wahr ?
Mein Beispielprogramm, das von einem IBM RT stammt, laeuft zu meinem
eigenen Erstaunen auch auf einer POWER2-Maschine, bei der die Parame-
ter normalerweise in Registern uebergeben werden.


> Der Code ist so hochgradig unportabel daß es sich gar nicht lohnt,
> darüber zu diskutieren.

Gerade da wird es doch interessant.


> Mein Rat: "man stdarg".

Das klappt nicht resp. lohnt den Aufwand nicht, s.o..


Was dagegen funktioniert:

[ ... ]
#include <varargs.h>
[ ... ]
void errmsg(fmt,va_alist)
char* fmt;
va_dcl /* expandiert zu 'int va_alist' */
{
typedef va_list vptype;

vptype adr;
char str[320+1];
int l;

/* adr=(vptype)&fmt+sizeof(fmt); */ /* FALSCH */
va_start(adr); /* Funktioniert */

l=sprintf(str,"%s: ",prcn);
(void)vsprintf(str+l,fmt,adr);
(void)fprintf(stderr,"%s\n",str);
}

Nur wuerde ich allerdings schon gerne wissen, was 'va_start' eigent-
lich anderes tut als meine auskommentierte Zeile oben - und das
herauszufinden ist nicht trivial. May the source be with GNU.


PORTABEL, da hast Du recht, ist das freilich nicht.

Danke fuer Deine Hinweise.

> Whom the gods would destroy, they first teach BASIC.

Was wollten die Goetter mit uns tun, als sie uns C schenkten ?

Hans Bonfigt

unread,
Jul 19, 2002, 7:16:37 AM7/19/02
to
Falk Hueffner:

>
> > adr=(vptype)&fmt+sizeof(fmt);
>
> Hier solltest du va_start nehmen; die Argumente muessen nicht
> unbedingt im Speicher liegen (in der Tat tun sie das bei den wenigsten
> Architekturen).

'va_start' tut ja auch nichts anderes als eine Adresse zu berechnen.
Allerdings macht es das offensichtlich besser als ich.

Danke fuer den Hinweis.

Claus Reibenstein

unread,
Jul 21, 2002, 8:05:01 AM7/21/02
to
Hans Bonfigt schrieb:

> Wolfgang Denk:


>
> > Niemand garantiert Dir, daß du die Adresse irgendwelchger Argumente
> > so bzw. überhaupt berechnen kannst; oft haben die gar keine Adresse
> > (sondern werden in Registern übergeben).
>
> Nicht wahr ?
> Mein Beispielprogramm, das von einem IBM RT stammt, laeuft zu meinem
> eigenen Erstaunen auch auf einer POWER2-Maschine, bei der die Parame-
> ter normalerweise in Registern uebergeben werden.

Das legt die Vermutung nahe, dass die Register memory-mapped sind.

> /* adr=(vptype)&fmt+sizeof(fmt); */ /* FALSCH */
> va_start(adr); /* Funktioniert */

> Nur wuerde ich allerdings schon gerne wissen, was 'va_start' eigent-


> lich anderes tut als meine auskommentierte Zeile oben - und das
> herauszufinden ist nicht trivial. May the source be with GNU.

Mein Vorschlag für die auskommentierte Zeile:

adr=(vptype)(&fmt+1); /* Richtig? */

> PORTABEL, da hast Du recht, ist das freilich nicht.

Meins auch nicht :-)

Gruß. Claus


0 new messages