On 2023-09-04 21:54, Kay Martinen <
use...@martinen.de> wrote:
> Am 04.09.23 um 22:33 schrieb Peter J. Holzer:
>> On 2023-09-04 19:53, Kay Martinen <
use...@martinen.de> wrote:
>>> Am 04.09.23 um 20:25 schrieb erzhausen:
>>>> Am 02.09.23 um 20:14 schrieb Kay Martinen:
>>>>> Ich habe hier ein Embedded Board (Portwell WADE ) mit einem Intel Atom
>>>>> N270 der m.W. ein 32-bit Prozessor ist.
>>>> ...
>>>> Hast du diesen Hinweis schon gesehen?
>>>>
https://www.debian.org/releases/stable/i386/release-notes/ch-information.de.html#i386-is-i686
>
>>> wenn die NOPL Instruktion vom bootkernel eines Debian Bookworm geprüft
>>> wird und er bei fehlen ohne kommentar einfach stehen bliebe. Denn...
>>
>> Ich halte es für viel wahrscheinlicher, dass er eben NICHT prüft, ob
>> diese Instruktion zur Verfügung steht, sondern sie einfach ausführt.
>> Wenn der Compiler Code für eine CPU generiert hat, der diese Instruktion
>> kennt, dann kann die an jeder Stelle im Code vorkommen. Eine Prüfung
>> wäre daher auch nur begrenzt sinnvoll, denn sie kann ja schon vor der
>> Prüfung vorkommen. Oder in dem Code der die Fehlermeldung ausgeben soll
>
> Das ist sicher richtig aber hier kann man nur vermuten. Ob z.b. die
> Kernelentwickler die Prüfungen auf die verschiedensten CPU-Features und
> Bugs (POPAD, PAE, ???) irgendwie hierarchisch-sequenziell sortiert durch
> führen so das nicht eine Prüfung durchfällt weil das feature das sie
> selbst braucht erst später geprüft wird.
>
> Stimme dir allerdings zu das man auch durch Vorab Prüfung beim
> kernelstart nicht wissen kann ob nicht später ein programm läuft das
> diese Instruktion einkompiliert hat. Ich erinnere mich das die CPU
> Exceptions wirft wenn sie einen illegalen Opcode findet. Kann man so was
> sinnvoll abfangen und NOPL durch x*NOP ersetzen
Könnte man, aber warum sollte man? Man kann ja den Kernel einfach für
das entsprechende CPU-Modell kompilieren. Da muss man keine speziellen
Tests oder Fault-Handler oder sonstwas programmieren, die das zur
Laufzeit fixen.
Dass Debian das nicht mehr macht, liegt wahrscheinlich daran, dass sie
die Zahl der Systeme, die noch eine so alte CPU haben, für
vernachlässigbar gering halten und es daher für sinnvoller halten, für
eine etwas neuere (aber immer noch sehr alte) Architektur zu
kompilieren.
> Ist die Frage hier nicht eher wozu ein Long NOP gut ist,
Es ist eine Instruktion, die mehrere Bytes lang ist und nichts macht.
> und ob er nicht auch durch mehrere NOP in folge ersetzt werden kann
Natürlich. Aber das sind dann halt mehrere Instruktionen. Macht also
länger nichts.
NOPs produziert der Compiler üblicherweise vor Sprungzielen, damit das
Sprungziel auf einer runden Adresse liegt. Z.B.:
int sum(int n) {
int s = 0;
for (int i = 1; i <= n; i++) {
s += i;
}
return s;
}
gcc -c -O2 -march=native foo.c
objdump -d foo.o
Disassembly of section .text:
0000000000000000 <sum>:
0: 85 ff test %edi,%edi
2: 7e 1c jle 20 <sum+0x20>
4: ff c7 inc %edi
6: b8 01 00 00 00 mov $0x1,%eax
b: 31 d2 xor %edx,%edx
d: 0f 1f 00 nopl (%rax)
10: 01 c2 add %eax,%edx
12: ff c0 inc %eax
14: 39 f8 cmp %edi,%eax
16: 75 f8 jne 10 <sum+0x10>
18: 89 d0 mov %edx,%eax
1a: c3 ret
1b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
20: 31 d2 xor %edx,%edx
22: 89 d0 mov %edx,%eax
24: c3 ret
Bei Adresse d (unmittelbar vor der Schleife ist hier ein NOPL mit 3
Bytes Länge. Damit wird der Anfang der Schleife auf Adresse 10
verschobeb. Die ist durch 16 teilbar, was die Abarbeitung der Schleife
schneller macht. Das einzelne NOPL davor dauert maximal 1 Takt (eher
0, weil es sich mit dem XOR vorher überlappt), drei NOPs mit je 1 Byte
könnten bis zu 3 Takte brauchen. Also produziert der Compiler lieber
eine Instruktion als drei.
> - oder durch eine Schleife die NOPs ausführt?
Nein, das ist nicht der Zweck von NOPs. Die sollen nicht Zeit
verbrauchen, sondern Platz.
> Natürlich nicht wenn fertige binaries ausgeführt werden, was ja erst
> nach dem Kernelstart mit PID 1 der fall sein kann.
Häh? Auch der Kernel ist ein fertiges Binary.
>>> und der einfach still sterben oder nichts mehr tun. Selbst einen
>>> kernel_panic könnte ich da eher als sinnvoll ansehen, aber.... NICHTS?
>>
>> Bei einer unbekannten Instruktion würde ich ein Oops erwarten, ja. Aber
>> eine so grundlegende Instruktion wie NOP kann natürlich auch im
>> Fault-Handler vorkommen.
>
> NOP wird wohl jede CPU können. Allerdings ging es hier ja um ein
> "langes" NOP. WasAuchImmerDasMacht.
Genau das gleiche, aber es braucht mehr Platz.
>> Oder die Instruktion kann auf einem älteren Prozessor einfach etwas
>> anderes machen.
> Z.b. als Illegaler Opcode eine Exception auslösen,
Nein, das war das vor dem "oder". Ich meinte, dass sie eben kein
illegaler Opcode ist und daher keine Exception auslöst, sondern
irgendwas undokumentiertes macht. Und in der nächsten
Prozessorgeneration hat Intel dann den "unbenützten" Opcode für ein NOP
verwendet (oder eher für eine neue sinnvolle Instruktion, die mit mit
bestimmten Parametern nichts macht. Ein "normales" NOP ist ja auch
einfach ein XCHG AX, AX oder etwas in der Art).
Ist zugeben bei einem Prozessor Baujahr 2008 nicht sehr wahrscheinlich.
> Ich weiß leider nicht wo, wie und warum man einen Langen NOP unbedingt
> braucht und warum der nun wichtig sein sollte.
Das NOPL an sich ist nicht wichtig. Es ist halt eine von diversen
Optimierungen die dem Compiler zur Verfügung stehen, wenn er für i686
Code erzeugt statt für i586. Wahrscheinlich ist es auch nicht die
einzige Instruktion, über die ein für i686 compilierter Kernel auf einem
i586 stolpern würde, aber NOPs in diversen Längen kommen halt in
compilergeneriertem Code so oft vor, dass das das erste ist, wo er sich
aufhängt. Im Allgemeinen kann Code, der für einen neueren Prozessor
einer Familie compiliert ist, auf älteren nicht ausgeführt werden.
hp