[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Programmierproblem



Hallo Eberhard
eberhard.hahn_bEi_zdv.uni-tuebingen.de meinte neulich zum Thema Programmierproblem
> dass die Toene viel zu kurz und zu hoch ausfallen.
>
> Wenn man z.B. das eingestrichene A (440 Hz) eine Sekunde lang ertoenen
> lassen will, wird man in Pascal oder C schreiben:
>
> 	sound(440);
> 	delay(1000);
> 	nosound;
>
> (In C muss es "nosound();" heissen.) Das funktioniert auf meinem 386er
> alles recht gut. Leider habe ich keinen Pentium-Rechner zur Verfuegung,
> auf dem ich experimentieren koennte, und auch mein Pascal-Compiler (TP
> 5.0) ist schon reichlich angegraut.
Mit Tcc, bcc und gcc habe ich auch keine Probleme. Die Funktionen delay() und
Sleep() laufen cpu-unabhaengig. Aber besonders die Borland Pascal-Compiler
scheinen die Funktion delay nicht ganz sauber implementiert zu haben. Das geht
teilweise soweit, dass Programme, die mit TP6 und TP7 uebersetzt wurden, auf
Maschinen Pentium 166 mHz aufwaerts mit einem Runtime error abstuerzen, wenn die
Delay-Funktion aufgerufen wird, weil irgendwo eine Division durch 0 auftritt.
Fuer dieses Problem gibt es einen Patch, der den Ausfuehrbaren Code dahingehend
modifiziert, dass diese 0-Division nicht mehr auftritt. Der behebt aber das
Problem mit den zu kurzen Toenen nicht. Die Dokumentation zu diesem Patcher
lautet wie folgt. Vielleicht gibt sie dir einige Hinweise.
 
tppatch.doc
----------.-
Hallo
 
Inzwischen wisst ihr ja alle von dem Bug in der Unit Crt, der auf sehr
schnellen Computern (200Mhz+) einen Runtime-Error 200 ausloest.
Der Fehler liegt im Startupcode von Delay(), bei einer Division wird das
Ergebnis zu gross und passt nicht mehr in das Zielregister.
 
Ich habe jetzt in den letzten Tagen einen Bugfix geschrieben, der alle mit
Pascal kompilierte EXE-Dateien patchen kann, darunter auch *Crosspoint*.
Dieses Verfahren funktioniert auch bei Programmen fuer den Protected Mode.
 
Der Patch ist nur fuer das Korrigieren von bereits kompilierten Programmen
vorgesehen, von denen man eventuell den Quellcode nicht hat.
Er behebt den eigentlichen Fehler naemlich nur teilweise.
 
Fuer Programme, die man noch programmiert und die man im Quellcode aendern
kann und will, gibt es ja inwzischen einige Loesungen.
 
Dadurch laeuft Delay auf allen langsamen Maschinen weiterhin korrekt,
ebenso wie auf Maschinen mit 200Mhz. Wenn es dann bald noch schnellere
Prozessoren gibt, wartet Delay() auf diesen dann aber zu wenig, aber
abstuerzen wird diese Stelle auf keinen Fall mehr.
 
Hier jetzt die Erklaerung:
 
>530B:0087 E83C02         call   02C6
>530B:008A F7D0           not    ax
>530B:008C F7D2           not    dx
>530B:008E B93700         mov    cx,0037
>530B:0091 F7F1           div    cx
                          ^^^^^^^^^
>530B:0093 A35C00         mov    [005C],ax
 
Diese Division an der Stelle CS:0091 bzw. CS:0099 verursacht eine
Exception #0 und damit einen Runtime-Error 200.
Die erste Prozedur (hier bei CS:0087) ermittelt, wie weit die CPU einen
Zaehler in ca. 55ms herunterzaehlen kann. Durch die beiden folgenden NOT-
Befehle wird der Wert negeriert und dann durch 55 geteilt. (37h=55d)
Dieser Wert, der dann in einer Variablen (hier [005C]) gespeichert wird,
wird spaeter in Delay() verwendet, um 1ms zu warten.
 
Ich habe die Stelle so abgeaendert:
 
>  cs:007E E88501         call   ....
>  cs:0081 F7D0           not    ax
>  cs:0083 F7D2           not    dx
>  cs:0085 B93700         mov    cx,0037
>  cs:0088 3BD1           cmp    dx,cx
>  cs:008A 7205           jb     0091
>  cs:008C B8FFFF         mov    ax,FFFF
>  cs:008F EB02           jmp    0093
>  cs:0091 F7F1           div    cx
>  cs:0093 A35C00         mov    [005C],ax
 
Dadurch wird verhindert, dass das Ergebnis spaeter groesser als ein Word
wird. Natuerlich musste ich dazu einige Befehle einfuegen. Um den Code nicht
komplett verschieben zu muessen, habe ich einige Nachlaessigkeiten der
Programmierer von BP/TP ausgenutzt, um vorher einige Bytes einzusparen,
z.B.:
 
vorher:
 
>  cs:0062 33C0           xor    ax,ax
>  cs:0064 A25100         mov    [0051],al
>  cs:0067 A26100         mov    [0061],al
>  cs:006A A26200         mov    [0062],al
>  cs:006D 40             inc    ax
>  cs:006E A25000         mov    [0050],al
 
nachher:
 
>  cs:0062 33C0           xor    ax,ax
>  cs:0064 A36100         mov    [0061],ax
>  cs:0067 40             inc    ax
>  cs:0068 A35000         mov    [0050],ax
 
 
Das Programm (TPPATCH.EXE) ueberprueft die zu patchende Datei genau, damit
nicht eine EXE-Datei "zu Tode gepatcht wird". Die Positionen der Variablen
werden automatisch gescannt, daher sollte der Patch mit allen Versionen
von TP7/BP7 arbeiten. Ich habe es nicht mit TP6 getestet (das habe ich
nicht). Es waere moeglich, das es auch dessen Dateien patchen kann.
-> Jedes Feedback ueber dieses Programm ist natuerlich willkommen.
 
Das ganze ist natuerlich nur notwendig, wenn auch die Unit CRT eingebunden
wurde.
 
Man kann durchaus per Batchdatei alle Dateien auf der Festplatte versuchen
zu patchen, denn es TPPATCH fuehrt zuerst eine ganze Reihe von Tests durch,
es wird also keiner anderen Datei ein Haar gekruemmt.
 
Gepackte EXE-Dateien muessen vor dem Patchen entpackt werden,
z.B. mit UNP (ftp://garbo.uwasa.fi/pc/execomp/unp411.zip).
 
Ich uebernehme natuerlich keine Verantwortung fuer alles, was man damit
anstellen kann. Vor dem Patchen von fremden Programmen sollte man einen
Blick in die LICENSE.DOC etc. werfen.
 
Sorry fuer das Binary, aber ich denke, das ist fuer jeden Programmierer, der
mit Pascal arbeitet, von Interesse.
 
Tschau
      Andreas