-
Die vorliegende Erfindung betrifft ein Verfahren zum Ausführen von auf einem Sicherheitsmodul ausführbarem Programmcode, ein entsprechendes Sicherheitsmodul, eine Menge solcher Sicherheitsmodule sowie ein Verfahren zum Erzeugen solchen Programmcodes.
-
Im Zusammenhang mit der vorliegenden Erfindung ist der Begriff des ausführbaren Programmcodes derart breit auszulegen, dass jedwede Form von Programmcode darunterfällt, der von Prozessoren, Interpretern, virtuellen Maschinen oder dergleichen ausgeführt bzw. interpretiert werden kann. Insofern ist darunter Programmcode zu verstehen, welcher gemäß einem so genannten Zwischencode codiert ist. Als Zwischencode wird vorliegend ein Code in einer Sprache verstanden, welche konzeptionell zwischen einem Code eines Quelltextes einer Hochsprache, beispielsweise „Java”, „C” oder dergleichen, auf der einen Seite und einer maschinennahen Zielsprache, insbesondere einem Maschinencode, auf der anderen Seite angeordnet ist.
-
Zwischencode kann von einem Compiler, beispielsweise im Rahmen einer Übersetzung (Compilierung) eines Quelltextes hin zu Maschinencode, als Zwischenergebnis erzeugt werden. Bekanntes Beispiel eines solchen Zwischencodes ist der so genannte „3-Adress-Code”. Zum Ausführen dieses Codes sind verschiedene Interpreter bekannt. Weitere bekannte Beispiele für ausführbaren Zwischencode, welcher von einem entsprechenden Compiler vorwiegend zum plattformunabhängigen Ausführen durch einen „virtuellen” Prozessor, beispielsweise eine Virtuelle Maschine, erzeugt wird, sind so genannte Bytecodes, wie z. B. Java- oder Java CardTM-Bytecode.
-
Anderseits kann unter „ausführbarem Programmcode” vorliegend auch Programmcode verstanden werden, welcher gemäß einer maschinennahen Zielsprache, insbesondere in Maschinencode, codiert ist. Programmcode dieser Art kann dann direkt von einem Hardware-Prozessor des Sicherheitsmoduls ausgeführt werden.
-
In neuerer Zeit stellen Angriffe auf portable Sicherheitsmodule, insbesondere Chipkarten, ein erhöhtes Sicherheitsrisiko sowohl für den individuellen Nutzer des Sicherheitsmoduls als auch für einen Hersteller der Sicherheitsmodule dar. Die Art der Angriffe ist mannigfaltig. Sie reicht beispielsweise von bloßem Abhören einer Datenkommunikationsverbindung zwischen einem solchen Sicherheitsmodul und einem Endgerät über das Auswerten des Ressourcenverbrauchs des Sicherheitsmoduls beim Durchführen einer Berechnung, beispielsweise des Stromverbrauchs oder der Rechenzeit, bis hin zu technisch sehr aufwendigen Angriffen. Dabei werden beispielsweise. Berechnungen des Prozessors des Sicherheitsmoduls gezielt dadurch gestört, dass mittels externen Einwirkens auf das Sicherheitsmodul, beispielsweise mittels gezielter Lichtblitze auf einzelne Speicherzellen eines Speichers des Sicherheitsmoduls, Eingabedaten oder Zwischenergebnisse einer Berechnung manipuliert werden, um anhand der dadurch erhaltenen, manipulierten Ergebnisse auf in dem Sicherheitsmodul gespeicherte sensible Daten, beispielsweise Verschlüsselungsschlüssel, zurückzuschließen.
-
Aus Sicht des individuellen Nutzers können bei einem solchen Angriff persönliche oder sonstige sensible Daten, beispielsweise geheime Schlüssel, ausgespäht werden. Für einen Hersteller der Sicherheitsmodule kann bereits ein erfolgreicher Angriff auf einen Sicherheitsmodul einer Serie baugleicher Sicherheitsmodule, neben dem Imageverlust, einen erheblichen Schaden bedeuten, da dann möglicherweise die ganze Serie von Sicherheitsmodulen als kompromittiert angesehen und daher zurückgerufen oder ersetzt werden muss.
-
Dies kann für einen Hersteller auch in dem Fall problematisch sein, in dem Sicherheitsmodule aus an sich verschiedenen Anwendungsbereichen, beispielsweise aus den Bereichen Telekommunikation, Banking, PayTV, etc., auf einer identischen Produktlinienarchitektur beruhen. Solche Sicherheitsmodule haben dann hinsichtlich der Ausführung von jeweils identisch darin vorliegendem Programmcode, beispielsweise von Teilen des Betriebssystems, dasselbe physikalische Verhalten, so dass ein erfolgreicher Angriff auf einen Sicherheitsmodule aus einem Anwendungsbereich, beispielsweise eine Kreditkarte, negative Auswirkungen auf die Sicherheit eines Sicherheitsmodules aus einem ganz anderen Bereich, beispielsweise eine SIM-Karte, haben kann.
-
Aufgabe der vorliegenden Erfindung ist es, Sicherheitsmodule mit darauf ausführbarem Programmcode gegen externe Angriffe zu schützen. Insbesondere sollen die Auswirkungen, welche ein erfolgreicher Angriff auf ein Sicherheitsmodul für andere, baugleiche Sicherheitsmodule hat, begrenzt werden.
-
Diese Aufgabe wird durch den Gegenstand der unabhängigen Ansprüche gelöst. Vorteilhafte Ausgestaltungen und Weiterbildungen sind in den abhängigen Ansprüchen angegeben.
-
Ein erfindungsgemäßes Verfahren zum Ausführen von ausführbarem Programmcode auf einem Sicherheitsmodul umfasst folgende Schritte: In einem ersten Schritt werden solche ausführbaren Programmcodeanteile des Programmcodes durch das Sicherheitsmodul erkannt, die nebenläufig ausführbar sind. In einem zweiten Schritt wird, ebenfalls durch das Sicherheitsmodul, eine sicherheitsmodulspezifische Reihenfolge festgelegt, in der die nebenläufig ausführbaren Programmcodeanteile bei einer sequentiellen Ausführung des Programmcodes durch das Sicherheitsmodul sequentiell ausgeführt werden sollen. Schließlich wird der Programmcode in einem dritten Schritt sequentiell durch das Sicherheitsmodul ausgeführt, wobei die nebenläufig ausführbaren Programmcodeanteile in der im zweiten Schritt festgelegten Reihenfolge sequentiell ausgeführt werden.
-
Ein erfindungsgemäßes Sicherheitsmodul umfasst einen Speicher und einen Prozessor zum Ausführen von in dem Speicher gespeichertem, ausführbarem Programmcode. Das Sicherheitsmodul zeichnet sich durch eine Erkennungseinrichtung aus. Diese ist eingerichtet, solche ausführbaren Programmcodeanteile des ausführbaren Programmcodes zu erkennen, die nebenläufig ausführbar sind. Weiter umfasst das Sicherheitsmodul erfindungsgemäß eine Reihenfolgenfestlegungseinrichtung, welche eingerichtet ist, eine sicherheitsmodulspezifische Reihenfolge festzulegen, in der die nebenläufig ausführbaren Programmcodeanteile bei einer sequentiellen Ausführung des Programmcodes durch das Sicherheitsmodul sequentiell ausgeführt werden sollen.
-
Eine erfindungsgemäße Menge solcher Sicherheitsmodule umfasst zumindest zwei Gruppen von Sicherheitsmodulen, wobei jede dieser Gruppen wiederum zumindest ein Sicherheitsmodul umfasst. Der jeweils in einem Speicher eines Sicherheitsmoduls gespeicherte, ausführbare Programmcode ist für jedes Sicherheitsmodul der Menge zumindest bezüglich der Anordnung nebenläufig ausführbarer Programmcodeanteile identisch. In der Regel stimmt der in das Sicherheitsmoduln verschiedener Gruppen gespeicherte, ausführbare Programmcode vollständig überein. Abweichungen im Programmcode rühren allenfalls von einer Optimierung einzelner Programmcodeanteile für Sicherheitsmodule vorgegebener Gruppen her, die nachfolgend näher beschrieben wird. Jedoch unterscheiden sich jeweils zwei Sicherheitsmodule aus unterschiedlichen der Gruppen von Sicherheitsmodulen, auch bei darin identisch vorliegendem Programmcode, hinsichtlich deren Laufzeitverhalten beim Ausführen des Programmcodes.
-
Das erfindungsgemäße Festlegen das Sicherheitsmodulspezifischen Reihenfolge, in der die nebenläufig ausführbaren Programmcodeanteile bei einer sequentiellen Ausführung des Programmcodes ausgeführt werden, bestimmt das Laufzeitverhalten der durch den ausführbaren Programmcode bereitgestellten Funktionalität. Es versteht sich, dass die Festlegung der Reihenfolge dabei derart erfolgt, dass die Gesamtfunktionalität, welche durch den ausgeführten Programmcode bereitgestellt wird, nicht beeinträchtig wird und für jede der möglichen, festlegbaren Reihenfolgen identisch ist.
-
Da jede festgelegte Reihenfolge sicherheitsmodulspezifisch ist, d. h. gruppenspezifisch oder sogar sicherheitsmodulindividuell, zeigt ein Sicherheitsmodul einer ersten Gruppe beim Ausführen des Programmcodes ein anderes Laufzeitverhalten als ein Sicherheitsmodul einer zweiten Gruppe beim Ausführen des Programmcodes.
-
Auf diese Weise werden die jeweiligen Sicherheitsmodule gegen externe Angriffe geschützt. Insbesondere kann ein Angreifer aus einem erfolgreichen Angriff auf ein Sicherheitsmodul der ersten Gruppe in der Regel keine Informationen gewinnen, welche für Angriffe auf Sicherheitsmodule der zweiten Gruppe nützlich sein könnten.
-
Wie bereits erwähnt, erfolgt das Festlegen einer sicherheitsmodulspezifischen Reihenfolge, in der die nebenläufig ausführbaren Programmcodeanteile sequentiell ausgeführt werden sollen, derart, dass sich beim Ausführen des Programmcodes ein Sicherheitsmodulspezifisches Laufzeitverhalten zeigt.
-
Gemäß einer ersten bevorzugten Ausführungsform des Verfahrens erfolgt das Festlegen dieser sicherheitsmodulspezifischen Reihenfolge, zumindest teilweise, randomisiert. Das bedeutet, dass zufällig erzeugte Werte das Festlegen der Reihenfolge zumindest beeinflussen. Dazu kann das Sicherheitsmodul bzw. die Reihenfolgenfestlegungseinrichtung des Sicherheitsmoduls beispielsweise auf einen (Pseudo)-Zufallsgenerator im Sicherheitsmodul zurückgreifen. Eine solche zufällige Ausführungsreihenfolge ist für einen Angreifer nicht vorhersehbar und nicht reproduzierbar. Dies erschwert bereits einen Angriff auf ein einzelnes Sicherheitsmodul, da Messwerte, welche das Laufzeitverhalten betreffen und welche während der Ausführung des Programmcodes erfasst werden, wie beispielsweise partielle Laufzeiten, Abstrahlung, Stromverbrauch, Belegung einzelner Speicherzellen oder Register, etc., für jede Ausführung des Programmcodes verschieden ausfallen können. Weiterhin ist die Wahrscheinlichkeit, dass die Ausführungsreihenfolge, die für einen zweites Sicherheitsmodul oder ein Sicherheitsmodul einer zweiten Gruppe – ebenfalls zufallsbasiert – festgelegt wird, mit der für ein erstes Sicherheitsmodul einer ersten Gruppe festgelegten übereinstimmt, zu vernachlässigen.
-
Gemäß einer zweiten bevorzugten Ausführungsform des Verfahrens kann das Festlegen einer sicherheitsmodulspezifischen Reihenfolge, in der die nebenläufig ausführbaren Programmcodeanteile sequentiell ausgeführt werden sollen, zumindest teilweise auf Basis einer in dem Sicherheitsmodul gespeicherten, sicherheitsmodulspezifischen Vorgabe erfolgen. Eine solche Vorgabe kann beispielsweise im Rahmen einer Personalisierung in das Sicherheitsmodul eingebracht werden. Die Vorgabe kann, wie erwähnt, gruppenspezifisch oder sicherheitsmodulindividuell sein.
-
In diesem Fall wäre die Ausführungsreihenfolge der entsprechenden Programmcodeanteile für jedes Ausführen des Programmcodes konstant. Es kann zusätzlich vorgesehen sein, dass die Vorgabe, beispielsweise in regelmäßigen oder unregelmäßigen Abständen oder in Abhängigkeit der Häufigkeit, mit der der Programmcode ausgeführt wird, geändert wird. Eine solche Änderung kann durch das Sicherheitsmodul selbst erfolgen oder von außen initiiert werden, beispielsweise durch einen Nutzer des Sicherheitsmoduls oder eine das Sicherheitsmodul ausgebende Stelle. Eine Änderung durch die ausgebende Stelle kann beispielsweise dann erfolgen, wenn das Sicherheitsmodul über ein Terminal mit dieser Stelle in Kontakt tritt.
-
Es versteht sich, dass beide Ausführungsformen nicht in reiner Form vorliegen müssen, sondern „gemischt” werden können. D. h. die Ausführungsreihenfolge kann sowohl auf zufällig erzeugten Werten als auch auf in dem Sicherheitsmodul gespeicherten, deterministischen Vorgaben beruhen. Es ist schließlich möglich, dass ein Sicherheitsmodul beide Ausführungsformen unterstützt und verwendet. Dabei kann, beispielsweise in regelmäßigen oder unregelmäßigen Abständen oder auf eine externe Eingabe hin, von einer zur anderen Ausführungsform oder zu einer Mischform gewechselt werden.
-
Sofern das Sicherheitsmodul in der Lage ist, anhand des ausführbaren Programmcodes zu erkennen, dass ein wiederholtes Ausführen eines der als nebenläufig ausführbar erkannten, ausführbaren Programmcodeanteile die Gesamtfunktionalität des Programmcodes nicht beeinträchtigt, kann diese Erkenntnis zusätzlich verwendet werden, um das Laufzeitverhalten beim Ausführen des Programmcodes zu variieren – und damit sicherheitsmodulindividuell zu gestalten. Ein oder mehrere entsprechende Programmcodeanteile können, beispielsweise zufallsbasiert, ausgewählt und bei einer Ausführung des Programmcodes mehrfach ausgeführt werden, wobei die entsprechende Anzahl wiederum, vorzugsweise randomisiert, variieren kann.
-
Schließlich ist es möglich, dass das Sicherheitsmodul das Ausführen eines als nebenläufig erkannten Programmcodeanteils während des Ausführens des Programmcodes, vorzugsweise randomisiert, verzögert. Auch dadurch ergibt sich eine Möglichkeit, ein beobachtbares Laufzeitverhalten zu variieren.
-
Der Schritt des Erkennens solcher ausführbaren Programmcodeanteile des Programmcodes, die nebenläufig ausführbar sind, kann auf verschiedene Arten erfolgen.
-
Gemäß einer ersten Variante können beispielsweise aus dem Gebiet des Compilerbaus bekannte Techniken verwendet werden, um ausführbaren Programmcode mit dem Ziel des Auffinden und Separieren nebenläufig ausführbarer Anteile zu analysieren. Entsprechende Funktionalitäten können durch die Erkennungseinrichtung des Sicherheitsmoduls implementiert sein. Auf diese Weise wird es beispielsweise möglich, dass ausführbarer Programmcode, welcher ursprünglich zum Ausführen auf einer Mehrkern- oder Mehrprozessorarchitektur erzeugt worden ist, um dort parallel ausgeführt zu werden, auf einem erfindungsgemäßen Sicherheitsmodul – sequentiell – gemäß dem erfindungsgemäßen Verfahren ausgeführt wird. Dazu werden diejenigen Programmcodeanteile, die zum parallelen Ausführen auf beispielsweise mehreren Prozessoren vorgesehen waren, d. h. von einem entsprechenden Compiler erzeugt worden sind, erfindungsgemäß als nebenläufig ausführbar erkannt – und nachfolgend sequentiell gemäß der festgelegten, sicherheitsmodulspezifischen Reihenfolge ausgeführt. Ebenso ist es möglich, dass der Programmcode bereits zur sequentiellen Ausführung erzeugt worden ist, gleichwohl aber nebenläufig ausführbare Programmcodeanteile umfasst. Gemäß dem Programmcode sind diese Anteile in einer vorgegebenen Reihenfolge zur sequentiellen Ausführung angeordnet. Erfindungsgemäß können diese Programmcodeanteile erkannt und deren Ausführungsreihenfolge sicherheitsmodulspezifisch neu festgelegt werden. Damit wird ein Sicherheitsmodulspezifisches Laufzeitverhalten beim Ausführen des Programmcodes erreicht, ohne dass der Programmcode an sich sicherheitsmodulspezifisch ausgebildet sein muss.
-
Gemäß einer zweiten Variante können die nebenläufig ausführbaren Programmcodeanteile von dem Sicherheitsmodul dadurch als nebenläufig ausführbar erkannt werden, dass diese Anteile in dem ausführbaren Programmcode bereits als nebenläufig ausführbar gekennzeichnet sind. D. h. der durch das Sicherheitsmodul auszuführende ausführbare Programmcode ist eigens für diese Variante erzeugt bzw. angepasst worden. Das Erkennen der nebenläufig ausführbaren Programmcodeanteile durch die Erkennungseinrichtung des Sicherheitsmoduls erfordert dann keine komplexe Analyse des Programmcodes mehr. Dies ist insbesondere für Sicherheitsmodule mit beschränkten Ressourcen, wie beispielsweise Chipkarten, vorteilhaft.
-
Ein erfindungsgemäßes Verfahren zum Erzeugen von ausführbarem Programmcode, welcher vorteilhaft gemäß der zuletzt beschriebenen Variante des Verfahrens zum Ausführen des Programmcodes ausgeführt werden kann, umfasst folgende Schritte:
In einem ersten Schritt wird ein dem Programmcode zugrunde liegender Quellcode, vorzugsweise in einer Hochsprache, wie z. B. „C”, „Java” oder dergleichen, bereitgestellt. Dann werden nebenläufig ausführbare Anteile der durch den Quellcode definierten Operationen ermittelt. Diese Anteile können dabei bereits auf der Ebene des Quellcodes ermittelt werden. Es ist aber auch möglich, dass dieser Schritt erst auf der Ebene eines Zwischencodes zwischen dem Quellcode und dem ausführbaren Programmcode oder erst auf der Ebene des ausführbaren Programmcodes stattfindet. Schließlich können nebenläufig ausführbare Anteile, mit Bezug auf denselben zu erzeugenden Programmcode, auch auf verschiedenen dieser Ebenen ermittelt werden. D. h. das Ermitteln der Anteile kann zu verschiedenen Zeitpunkten und in verschiedenen Phasen einer Übersetzung des Quellcodes zu ausführbarem Programmcode durchgeführt werden.
-
In einem weiteren Schritt wird ausführbarer Programmcode aus dem Quellcode erzeugt. Erfindungsgemäß werden im Schritt des Erzeugen des ausführbaren Programmcodes ausführbare Programmcodeanteile, die zuvor ermittelten, nebenläufig ausführbaren Anteilen entsprechen, als nebenläufig ausführbar gekennzeichnet. Die Art der Kennzeichnung kann variieren. Bekannte Kennzeichnungs- oder Codierungstechniken können verwendet werden.
-
In einem optionalen Schritt können die als nebenläufig ausführbar gekennzeichneten, ausführbaren Programmcodeanteile für eine sequenzielle Ausführbarkeit des erzeugten Programmcodes angeordnet werden. Dieser Schritt kann eine Modifikation der Programmcodeanteile umfassen. Eine solche Modifikation kann beispielsweise dazu dienen, ursprünglich zur parallelen Ausführung auf einer Mehrkern- oder Mehrprozessorarchitektur vorgesehenen Programmcode für eine sequentielle Ausführung anzupassen, falls dies notwendig ist.
-
Als „nebenläufig ausführbar” werden im Zusammenhang mit der vorliegenden Erfindung solche Anteile der durch den Quellcode definierten Operationen verstanden, die paarweise keine kausale Beziehung zueinander aufweisen. Eine solche kausale Beziehung könnte insbesondere darin bestehen, dass eine Berechnung, welche durch Programmcodeanteile entsprechend einem ersten Anteil durchgeführt wird, von Ergebnissen einer Berechnung, welche durch Programmcodeanteile entsprechend einem zweiten Anteil erfolgt, direkt oder indirekt abhängt oder beeinflusst wird. Zwei Anteile, beispielsweise zwei Transaktionen, Prozesse oder Threads, sind somit genau dann nebenläufig ausführbar oder parallelisierbar, wenn eine zeitlich parallele Ausführung, eine verzahnte Ausführung oder eine sequentielle Ausführung in geänderter Reihenfolge zu demselben Resultat führt wie ein sequentielles Ausführen gemäß einer vorgegebenen Reihenfolge.
-
Dabei kann es Anteile geben, die in gewissem Sinne „global” nebenläufig ausführbar sind, d. h. Anteile, die zu keinem anderen Anteil der durch den Quellcode definierten Operationen kausal in Beziehung stehen. Im Allgemeinen aber wird der Begriff „Nebenläufigkeit” als relativer Begriff in dem Sinne verstanden werden müssen, dass eine vorgegebene Menge von Anteilen, paarweise und relativ zueinander, nebenläufig, d. h. beispielweise zeitlich parallel oder in abgeänderter Reihenfolge, ausgeführt werden können. Dies sagt dann allerdings nichts darüber aus, ob, und wenn ja, welche kausale Beziehung zwischen einem oder mehreren dieser Anteile zu anderen, nicht zu der entsprechenden, vorgegebenen Menge von Anteilen gehörenden Anteilen bestehen. Schließlich können nebenläufig ausführbare Anteile auch in verschachtelter Weise auftreten, beispielweise im Falle einer Menge nebenläufig ausführbarer Anteile, die einen oder mehrere Anteile umfassen, welche ihrerseits aus nebenläufig ausführbaren Unteranteilen bestehen.
-
Die allgemeine Formulierung „Ermitteln von nebenläufig ausführbaren Anteilen” mit Bezug auf das erfindungsgemäße Verfahren zum Erzeugen vom Programmcode und die Formulierung „Erkennen von ausführbaren Programmcodeanteilen, die nebenläufig ausführbar sind” mit Bezug auf das erfindungsgemäße Verfahren zum Ausführen vom Programmcode umfasst somit jede dieser Arten von global und/oder relativ zu anderen Anteilen nebenläufig ausführbaren Anteilen. Wie aus dem Vorstehenden ersichtlich, ist der Begriff „Ermitteln von nebenläufig ausführbaren Anteilen” breiter zu verstehen und umfasst den Begriff des „Erkennens von Programmcodeanteilen, die nebenläufig ausführbar sind”. Das „Ermitteln” kann, wie beschrieben, auf einer oder mehreren Stufen (Quellcode, Zwischencode, ausführbarer Programmcode) stattfinden, das „Erkennen” erfolgt lediglich anhand des vorliegenden, erzeugten ausführbaren Programmcodes.
-
Weiter gilt, dass im Schritt des Festlegens der datenspezifischen Ausführungsreihenfolge im Verfahren zum Ausführen von Programmcode, die Art und der Umfang der nebenläufigen Ausführbarkeit beachtet werden. D. h. eine sicherheitsmodulspezifische Festlegung einer Position eines ausführbaren Programmcodeanteils innerhalb einer Reihenfolge ausführbarer Programmcodeanteile im erzeugten Programmcode zur nachfolgenden sequentiellen Ausführbarkeit erfolgt stets relativ zu den entsprechenden, mit Bezug auf diesen ausführbaren Programmcodeanteil nebenläufig ausführbaren Programmcodeanteilen.
-
Im Rahmen des Schritts des Ermitteln von nebenläufig ausführbaren Anteilen im Verfahren zur Erzeugung vom Programmcode kann eine Anzahl von gleichzeitig nebenläufig ausführbaren Anteilen vorgegeben werden. Diese Anzahl von gleichzeitig nebenläufig oder parallel ausführbaren Anteilen entspräche, wenn Programmcode zum Ausführen auf einer Mehrkern- oder Mehrprozessorarchitektur erzeugt werden sollte, beispielsweise der Anzahl der dort bereitstehenden Kerne oder Prozessoren. Je größer diese Anzahl gewählt oder vorgegeben wird, desto großer ist die Anzahl von möglichen, späteren Ausführungsreihenfolgen entsprechender Anteile bei einer sequentiellen Ausführung des entsprechenden Programmcodes.
-
Diejenigen ausführbaren Programmcodeanteile, die ermittelten, nebenläufig ausführbaren Anteilen entsprechen, können beim Erzeugen des ausführbaren Programmcodes in einer Tabelle angeordnet werden. Dies erlaubt auf besonders einfache Weise, nebenläufig ausführbare Programmcodeanteile zu kennzeichnen. Es muss lediglich die Tabelle gekennzeichnet werden. Ebenfalls vereinfacht wird gemäß dieser Ausführungsform mit Blick auf das beschriebene Verfahren zum Ausführen des Programmcodes das Festlegen einer Ausführungsreihenfolge der entsprechenden, nebenläufig ausführbaren Programmcodeanteile. Diese Reihenfolge kann beispielsweise bereits durch eine Permutation der Tabelleneinträge definiert und festgelegt werden.
-
Grundsätzlich können nebenläufig ausführbare Anteile der durch den bereitgestellten Quellcode definierten Operationen in allgemeiner Weise, auch aus einem bereits für eine sequentielle Ausführung angelegten Programmcode, ermittelt werden. Einige bekannte Programmstrukturen eignen sich allerdings besonders zur Parallelisierung, wie beispielsweise Schleifen. D. h. als nebenläufig ausführbare Anteile der durch den Quellcode definierten Operationen können bevorzugt eine Schleifenoperation definierende Anteile ermittelt werden. Eine Schleife beispielsweise der Form (for i = 0; i < 1000; i++){a[i] := i} kann in bis zu 1000 Anteile aufgeteilt werden, jeder Anteil entsprechend zumindest einem Schleifendurchlauf, welche jeweils nebenläufig ausgeführt werden können. In gleicher Weise können als nebenläufig ausführbare Anteile eine geeignete Rekursion definierende Anteile ermittelt werden. Dies gilt insbesondere dann, wenn in einem Rekursionsaufruf dieselbe Funktion mehr als einmal, unabhängig voneinander und mit verschiedenen Parametern, aufgerufen wird, wie dies beispielsweise bei einer bekannten, rekursiven Implementation des Quick-Sort-Algorithmus der Fall ist.
-
Gemäß einer weiteren bevorzugten Ausführungsform kann zumindest einer der ausführbaren Programmcodeanteile, der einem nebenläufig ausführbaren Anteil entspricht, im Schritt des Erzeugens des ausführbaren Programmcodes hinsichtlich zumindest eines vorgegebenen Parameters optimiert werden. Bevorzugte Parameter sind beispielsweise Laufzeit und/oder Speicherbedarf. Diese Optimierung kann vor oder nach das Sicherheitsmodulspezifischen Anordnung mit Bezug auf die anderen ausführbaren Programmcodeanteile erfolgen, welche ebenfalls nebenläufig ausführbaren Anteilen entsprechen. Die Optimierung kann weiterhin in einer oder mehreren verschiedenen Phasen eines Übersetzungsprozesses vom Quellcode zum ausführbaren Programmcode erfolgen, also beispielsweise auch bereits auf Ebene eines Zwischencodes.
-
Auf diese Weise kann der erzeugte ausführbare Programmcode, im Vergleich zu einem entsprechenden Programmcode ohne Optimierung, ebenfalls sicherheitsmodulspezifisch ausgebildet werden. Eine Optimierung bezüglich Laufzeit, auch wenn diese nur einzelne Teilfunktionalitäten betrifft, verändert das Laufzeitverhalten der durch den erzeugten, ausführbaren Programmcode bereitgestellten Gesamtfunktionalität. Eine – auch nur teilweise – Optimierung bezüglich des Speicherbedarfs beeinflusst das gesamte Speicherabbild. Eine solche Optimierung kann überdies die Behandlung lokaler Variablen im Bereich der optimierten, ausführbaren Programmcodeanteile beeinflussen, und somit während der Laufzeit beispielsweise auch die Belegung eines Stapelspeichers, verschiedener Prozessorregister oder anderer Speicherbereiche, beispielsweise im Arbeitsspeicher des Prozessors.
-
Besonders bevorzugt werden verschiedene der ausführbaren Programmcodeanteile, die nebenläufig ausführbaren Anteilen entsprechen, jeweils hinsichtlich verschiedener Parameter optimiert. Auf diese Weise ergeben sich vielfältige, weitere Möglichkeiten des Sicherheitsmodulspezifischen Erzeugens des ausführbaren Programmcodes.
-
Gemäß einer weiteren bevorzugten Ausführungsform des Verfahrens zum Erzeugen des Programmcodes wird der Schritt des Ermitteln von nebenläufig ausführbaren Anteilen der durch den Quellcode definierten Operationen von einer Einrichtung durchgeführt oder durch eine solche Einrichtung zumindest unterstützt, welche zum Erzeugen von auf einer Mehrkern und/oder Mehrprozessorarchitektur parallel ausführbarem Programmcode eingerichtet ist. Eine solche Einrichtung kann auf verschiedenen Ebenen eingreifen oder wirken, beispielsweise in Form von in den Quellcode einfügbaren Compilerdirektiven oder, bei unverändertem Quellcode, durch Funktionalitäten des Compilers selbst.
-
D. h. eine solche bereits vorliegende, bekannte Einrichtung, beispielsweise ein Compiler zum Erzeugen von parallel ausführbarem Programmcode, wird erfindungsgemäß „zweckentfremdet”, indem durch diese Einrichtung erzeugter, parallel auf einer Mehrprozessorarchitektur ausführbarer Programmcode als Zwischenergebnis verwendet wird. Der aufwendige und in der Regel komplexe Schritt des Ermitteln von nebenläufig ausführbaren Anteilen wird vollständig von dieser Einrichtung übernommen und, in der Regel zusätzlich konfigurierbar, durchgeführt.
-
Zum erfindungsgemäßen Erzeugen des sequenziell ausführbaren Programmcodes ist es abschließend lediglich erforderlich, die von der Einrichtung für eine jeweils parallele Ausführung vorgesehenen Anteile, wie beispielsweise parallel ausführbare Threads oder dergleichen, zu kennzeichnen. Optional können diese Anteile, wie erwähnt, für eine sequentielle Ausführung auf einem Sicherheitsmodul mit nur einem Prozessor modifiziert und angeordnet werden.
-
Im Rahmen des Verfahrens zum Ausführen des Programmcodes wird dann ein vermeintlicher Nachteil der parallelen Programmierung, nämlich das notwendig daraus resultierende, nicht genau vorhersehbare Laufzeitverhalten einer entsprechenden, parallelisierten Anwendung, erfindungsgemäß in einen Vorteil umgemünzt, indem nämlich die Nichtvorhersehbarkeit des Laufzeitverhaltens, welche erfindungsgemäß ein Sicherheitsmerkmal des Sicherheitsmoduls ist, durch eine sicherheitsmodulspezifische Festlegung der Reihenfolge der Ausführung parallelisierbarer Anteile zur sequentiellen Ausführung noch verstärkt wird.
-
Ein Sicherheitsmodul ist vorzugsweise ein Hardware-Sicherheitsmodul. Das Sicherheitsmodul kann ein tragbarer Datenträger sein, wie beispielsweise eine Chipkarte, ein USB-Token, ein RFID-Token oder eine sichere Massenspeicherkarte. Das Sicherheitsmodul kann reversibel mit einem Endgerät verbunden werden oder fest in ein Endgerät eingebaut sein, wie beispielsweise ein eingebautetes SIM-Modul (eUICC), ein TPM-Modul oder NFC-Modul.
-
Die vorliegende Erfindung wird im Folgenden mit Bezug auf die beiliegenden Zeichnungen beispielhaft beschrieben. Darin zeigen:
-
1 eine bevorzugte Ausführungsform eines erfindungsgemäßen Datenträgers;
-
2 eine bevorzugte Ausführungsform einer erfindungsgemäßen Menge von Datenträgern, unterteilt in einzelne Gruppen, mit dem Datenträger aus 1 als Element einer ersten Gruppe;
-
3 Schritte einer bevorzugten Ausführungsform eines erfindungsgemäßen Verfahrens zum Ausführen von Programmcode;
-
4 Schritte einer bevorzugten Ausführungsform eines erfindungsgemäßen Verfahrens zum Erzeugen von ausführbarem Programmcode;
-
5A bis 5C Ergebnisse einzelner Teilschritte von Verfahrensschritten aus 3 und 4.
-
Mit Bezug auf 1 umfasst ein Datenträger 10 als Sicherheitsmodul, der hier als Chipkarte dargestellt ist, Datenkommunikationsschnittstellen 20, 20', einen Prozessor 30 sowie verschiedene Speicher 40, 50 und 60. Der Datenträger 10 kann auch in anderer Bauform vorliegen.
-
Als Datenkommunikationsschnittstellen 20, 20' umfasst der Datenträger 10 ein Kontaktfeld 20 zur kontaktbehafteten Datenkommunikation sowie eine Antennenspule 20' zur kontaktlosen Datenkommunikation. Alternative Datenkommunikationsschnittstellen können vorgesehen sein. Es ist weiterhin möglich, dass der Datenträger 10 lediglich eine Art der Datenkommunikation unterstützt, also lediglich kontaktbehaftet oder kontaktlos.
-
Der nicht flüchtige, nicht wiederbeschreibbare ROM-Speicher 40 umfasst ein Betriebssystem (OS) 42 des Datenträgers 10, welches den Datenträger 10 steuert. Zumindest Teile des Betriebssystems 42 können auch in dem nicht flüchtigen, wiederbeschreibbaren Speicher 50 gespeichert sein. Dieser kann beispielsweise als FLASH-Speicher vorliegen.
-
Der Speicher 50 umfasst ausführbaren Programmcode 52. Gemäß einer Variante kann dieser Programmcode, wie nachfolgend mit Bezug auf die 4 bis 5C beschrieben, erzeugt worden sein. Weiter umfasst der Speicher 50 eine Erkennungseinrichtung 54, welche in der Regel als Softwareapplikation vorliegt. Die Erkennungseinrichtung 54 ist, wie mit Bezug auf die 3 und 5A bis 5C nachstehend detailliert beschrieben, eingerichtet, solche ausführbaren Programmcodeanteile B, C, D (vgl. 5A) des ausführbaren Programmcodes 52 zu erkennen, die nebenläufig ausgeführt werden können. Weiter umfasst der Speicher 50 eine in der Regel ebenfalls als Softwareapplikation bereitgestellte Reihenfolgenfestlegungseinrichtung 56. Diese ist, wie nachstehend mit Bezug auf 3 beschrieben, eingerichtet, eine datenträgerspezifische Reihenfolge festzulegen, in der die nebenläufig ausführbaren Programmcodeanteile B, C, D bei einer sequentiellen Ausführung des Programmcodes 52 durch den Datenträger 10 sequentiell ausgeführt werden sollen (vgl. 3, 5A–C).
-
Der flüchtige, wiederbeschreibbare RAM-Speicher 60 dient dem Datenträger 10 als Arbeitsspeicher.
-
Wie in 2 gezeigt, liegen weitere Datenträger 10', 10'' einer Menge 100 von Datenträgern, unterteilt in verschiedene Gruppen 101, 102, 103, vor. Datenträger innerhalb einer Gruppe sind hinsichtlich der beschriebenen Komponenten jeweils identisch. Datenträger 10, 10', 10'' unterschiedlicher Gruppen 101, 102, 103 unterscheiden sich darin, dass die Funktionalität, welche durch den ausführbaren Programmcode 52 bereitgestellt wird, jeweils ein gruppenspezifisches Laufzeitverhalten aufweist. Die durch den Programmcode 52 bereitgestellte Funktionalität ist allerdings für alle Datenträger 10, 10', 10'' der Menge 100 von Datenträgern, unabhängig von der Gruppenzugehörigkeit 101, 102, 103, identisch. Das gruppenspezifische, jeweils unterschiedliche Laufzeitverhalten beruht, wie nachfolgend mit Bezug auf 3 beschrieben, darauf, dass die jeweils in den Datenträgern 10, 10', 10'' vorliegende Reihenfolgenfestlegungseinrichtung 56, 56', 56'' die Reihenfolge, in der nebenläufig ausführbare Programmcodeanteile B, C, D bei einer sequentiellen Ausführung des Programmcodes 52 ausgeführt werden, gruppenspezifisch festlegt. Diese Festlegung erfolgt erst zur Laufzeit, d. h. während der Ausführung des Programmcodes 52. Ein Ausführen kann dabei, wie erwähnt, auch ein Interpretieren umfassen.
-
Mit Bezug auf 3 werden im Folgenden einzelne Schritte eines Verfahrens zum Ausführen von ausführbarem Programmcode 52 auf dem Datenträger 10 beschrieben.
-
In einem ersten Schritt T1 analysiert die Erkennungseinrichtung 54 des Datenträgers 10 den Programmcode 52 zum Erkennen nebenläufig ausführbarer Programmcodeanteile B, C, D.
-
Dabei kann die Erkennungseinrichtung 54 grundsätzlich eingerichtet sein, zur sequentiellen oder parallelen Ausführung erzeugten, ausführbaren Programmcode 52 mittels bekannter, nachstehend mit Bezug auf die 3A bis 3C mit Bezug auf Schritt S2 des Verfahrens aus 4 beschriebener Verfahren zu untersuchen und dabei nebenläufig ausführbare Programmcodeanteile B, C, D zu erkennen.
-
Gemäß einer bevorzugten Variante erkennt die Erkennungseinrichtung 54 nebenläufig ausführbare Programmcodeanteile B, C, D allerdings daran, dass diese im Programmcode 52 bereits als solche, d. h. als nebenläufig ausführbar, explizit gekennzeichnet sind. Die Art der Kennzeichnung kann dabei variieren. Ein entsprechender Programmcode 52, der bereits als nebenläufig ausführbar gekennzeichnete Programmcodeanteile B, C, D, umfasst, kann beispielsweise mit einem Verfahren, welches nachfolgend mit Bezug auf 4 beschrieben wird, erzeugt werden.
-
In einem weiteren Schritt T2 des Verfahrens zum Ausführen des Programmcodes 52 auf dem Datenträger 10 legt die Reihenfolgenfestlegungseinrichtung 56 die Reihenfolge fest, in der die in Schritt T1 als nebenläufig ausführbar erkannten Programmcodeanteile B, C, D bei einer sequentiellen Ausführung des Programmcodes 52 in dem Datenträger 10 ausgeführt werden sollen. Diese Festlegung erfolgt zur Laufzeit. Die festgelegte Ausführungsreihenfolge ist dabei spezifisch für den Datenträger 10 bzw. die Gruppe 101, der der Datenträger 10 angehört, und unterscheidet sich von einer für einen Datenträger 10', 10'' einer anderen Gruppe 102, 103 festgelegten Reihenfolge. Damit wird das Ziel erreicht, dass Datenträger 10, 10', 10'' verschiedener Gruppen 101, 102, 103 beim Ausführen des gleichen Programmcodes 52 jeweils ein unterschiedliches Laufzeitverhalten aufweisen, mithin die während der Ausführung für einen Angreifer messbaren oder beobachtbaren Parameter, wie beispielsweise Stromverbrauch oder Abstrahlung des Datenträgers, jeweils unterschiedlich sind.
-
Gemäß einer ersten Variante legt die Reihenfolgenfestlegungseinrichtung 56 diese Ausführungsreihenfolge bei jeder Ausführung des Programmcodes 52 neu fest. Bevorzugt erfolgt die Festlegung zumindest teilweise randomisiert, d. h. unter Einsatz (pseudo-)zufällig erzeugter Werte. Dazu kann der Datenträger 10 einen Zufallsgenerator (nicht gezeigt) umfassen.
-
Gemäß einer zweiten Variante erfolgt die Festlegung deterministisch. In der Regel ist diese Festlegung dann für mehrere aufeinanderfolgende Ausführungen des Programmcodes 52 konstant. Dies kann beispielsweise dadurch erreicht werden, dass der Algorithmus, der zur Festlegung der Reihenfolge verwendet wird, durch die Reihenfolgenfestlegungseinrichtung 56 vollständig bestimmt ist und – bis auf die Anzahl der jeweils nebenläufig ausführbaren Programmcodeanteile B, C, D – keine weiteren Eingaben benötigt. Eine deterministische Festlegung kann alternativ auf einer in dem Datenträger 10 gespeicherten Vorgabe (nicht gezeigt) beruhen. Andere Arten der deterministischen Festlegung sind möglich.
-
Gemäß einer dritten Variante werden sowohl zufällige als auch deterministische Eingaben verwendet, um die Ausführungsreihenfolge festzulegen.
-
Es ist möglich, dass Regeln oder Vorgaben, welche die Reihenfolgenfestlegungseinrichtung 56 zur Festlegung der Reihenfolge, in der die nebenläufig ausführbaren Programmcodeanteile B, C, D bei einer sequentiellen Ausführung des Programmcodes 52 ausgeführt werden sollen, von Zeit zu Zeit geändert werden. Dies kann aufgrund verschiedener Ereignisse erfolgen, beispielsweise als Folge einer entsprechenden Änderungseingabe eines Nutzers des Datenträgers 10, aufgrund einer Datenkommunikation mit einer den Datenträger 10 ausgebenden Stelle oder dergleichen. Ein anderes Ereignis kann ein erkannter oder vermuteter Angriff auf den Datenträger 10 sein. Eine Änderung der Regel und/oder Vorgaben kann aber auch abhängig von einer Anzahl erfolgter Ausführungen des Programmcodes 52 durch den Datenträger 10 sein oder aber zu regelmäßig oder unregelmäßig, z. B. zufällig gewählten Zeitpunkten erfolgen.
-
In einem dritten Schritt T3 schließlich wird der Programmcode 52 auf dem Datenträger 10 sequentiell ausgeführt. Dabei werden die nebenläufig ausführbaren Programmcodeanteile in der wie vorstehend beschrieben festgelegten Reihenfolge sequentiell ausgeführt. Das Interpretieren oder Ausführen des Programmcodes 52 kann dabei, abhängig von der Art des Programmcodes 52, durch einen Virtuellen Prozessor (nicht gezeigt), beispielsweise eine Virtuelle Maschine, erfolgen, falls der Programmcode 52 beispielsweise als Byte-Code vorliegt, oder durch den Prozessor 30 des Datenträgers 10, wenn der Programmcode 52 dafür erzeugt worden ist.
-
Mit Bezug auf 4 werden im Folgenden einzelne Schritte eines Verfahrens zum Erzeugen eines ausführbaren Programmcodes 52 für den Datenträger 10 beschrieben, welcher geeignet ist, mit den vorstehend mit Bezug auf 3 beschriebenen Verfahren auf dem Datenträger 10 ausgeführt zu werden.
-
In Schritt S1 wird ein Quellcode bereitgestellt. Dieser Quellcode definiert diejenigen Operationen, welche durchgeführt werden müssen, um die gewünschte Funktionalität bereitzustellen. Der Quellcode liegt in der Regel in einer Hochsprache, beispielsweise in „C”, „Java” oder dergleichen vor.
-
In Schritt S2 werden nebenläufig ausführbare Anteile der durch den Quellcode definierten Operationen ermittelt. Ausführbarer Programmcode 52 wird in Schritt S3 erzeugt, wobei in Teilschritt S31 nebenläufig ausführbare Anteile, wie bereits erwähnt, als solche gekennzeichnet werden. In einem optionalen Teilschritt S32 können die als nebenläufig ausführbar gekennzeichneten Programmcodeanteile für eine sequentielle Ausführung des erzeugten Programmcodes 52 angeordnet werden. Dieser Schritt kann beispielsweise unterbleiben, wenn die vorstehend beschriebene Erkennungseinrichtung 54 entsprechende Funktionalitäten unterstützt.
-
In einem optionalen vierten Schritt S4 können einzelne als nebenläufig ausführbar ermittelten Anteile und/oder die dazugehörigen, erzeugten, ausführbaren Programmcodeanteile nach verschiedenen Kriterien optimiert werden. Auch die Optimierung kann bereits während, d. h. im Rahmen des Übersetzungsprozesses, also beim Erzeugen des ausführbaren Programmcodes, erfolgen, bevor beispielsweise abschließend ausführbarer Maschinencode erzeugt wird.
-
Eine mögliche Vorgehensweise zum Ermitteln nebenläufig ausführbarer Anteile ist in den 5A bis 5C skizziert.
-
Sofern keine Missverständnisse zu erwarten sind, wird im Folgenden nur noch von „nebenläufig ausführbaren Anteilen” gesprochen, ohne genau zu unterscheiden, auf welcher Ebene diese gerade betrachtet werden. Dies kann beispielsweise die Ebene des Quellcodes, die Ebene eines Zwischencodes oder die Ebene eines Maschinencodes betreffen, je nachdem in welcher Phase eines nachfolgend grob skizzierten Übersetzungsprozesses diese Anteile bestimmt werden. D. h. eine Quellcodesequenz, welche beispielsweise eine Schleifenoperation codiert und in nebenläufig ausführbare Anteile zerlegt werden kann, wird in diesem Sinne mit der entsprechend in den Zwischencode übersetzten Sequenz bzw. mit dem Stück ausführbaren Maschinencode gleichgesetzt, welcher diese Schleifenoperation für den Prozessor codiert.
-
Das Ermitteln der nebenläufig ausführbaren Anteile erfolgt in der Regel im Rahmen einer Übersetzung oder Compilierung des Quellcodes in den ausführbaren Programmcode. Ein Erkennen von nebenläufig ausführbaren Programmcodeanteilen kann allerdings auch auf Basis von bereits erzeugtem. ausführbarem Programmcode (Zwischencode, Maschinencode) erfolgen (vgl. Schritt T1 in 3).
-
Eine genannte Übersetzung verläuft in bekannter Weise in verschiedenen Teilschritten. Diese können die Schritte der lexikalischen Analyse, der Syntaxanalyse, der semantischen Analyse, der Erzeugung von Zwischencode, der Codeoptimierung und der Codeerzeugung umfassen. Phasen, welche das Ermitteln der nebenläufig ausführbaren Anteile hauptsächlich betreffen können, sind beispielsweise die Syntaxanalyse, in der hierarchische Strukturen des Programms erkannt werden. Alternativ oder zusätzlich können nebenläufig ausführbare Anteile während der Erzeugung von Zwischencode ermittelt werden, bei der die Ergebnisse der vorhergehenden Schritte, welche zur Analyse des Quellcodes dienten, in eine „abstrakte Maschinensprache”, einen geeigneten Zwischencode, wie z. B. den 3-Adress-Code, übersetzt werden, von dem aus dann nachfolgend der tatsächliche Maschinencode für die vorliegende Plattform erzeugt wird. Es ist aber auch möglich, dass nebenläufig ausführbare Anteile, zumindest grob, bereits auf der Ebene des Quellcodes, also vor der Übersetzung, oder, wie erwähnt, erst auf der Ebene des Maschinencodes, d. h. am Ende der Übersetzung, ermittelt werden. Schließlich können verschiedene, nebenläufig ausführbare Anteile in verschiedenen der vorstehend beschriebenen Phasen oder in mehr als einer Phase bestimmt werden.
-
Ein erster Teilschritt während des Ermittelns von nebenläufig ausführbaren Anteilen, der in 3A illustriert ist, kann eine Zerlegung des Programmcodes, auf einer geeigneten Ebene des Programmcodes 51, in Blöcke betreffen. Jeder dieser Blöcke A bis G umfasst jeweils eine Folge von Anweisungen, welche, wenn der Block erreicht wird, ausgeführt werden müssen, bevor der Block wieder verlassen wird. Es ist jedoch möglich, dass die Reihenfolge, in der einzelne der Blöcke ausgeführt werden können, variieren kann, ohne Einfluss auf das Endergebnis. In analoger Weise ist es möglich, dass Anweisungen innerhalb eines Blockes in verschiedener Reihenfolge ausgeführt werden können, ohne dass sich am Resultat der Berechnung etwas ändert. Diese beiden Fälle deuten auf nebenläufig ausführbare Anteile hin.
-
Wie mit Bezug auf 3B angedeutet, hat der bis dahin durchgeführte Übersetzungs- oder Analyseprozess ergeben, dass die Blöcke A bis G nicht notwendig in der in 3A angedeuteten Reihenfolge ausgeführt werden müssen. Vielmehr zeigt sich, dass, nachdem die Anweisungen des Blocks A abgearbeitet worden sind, die Blöcke B, C und D parallel, verzahnt oder in beliebiger sequentieller Reihenfolge ausgeführt werden können, bevor das Programm mit Block E fortgesetzt wird. Mit anderen Worten, es besteht keine kausale Beziehung zwischen den Anteilen der Blöcke B, C und D. Keiner dieser Blöcke benötigt eine Eingabe, welche in direkter oder indirekter Weise von einer Ausgabe eines der anderen Blöcke abhängen könnte. Daher können diese Blöcke als – relativ zueinander – nebenläufig ausführbar ermittelt werden. Das gleiche gilt für die Unteranteile F1, F2, ..., Fk des Anteils gemäß Block F.
-
Gemäß einer ersten Variante kann ausgehend von diesem Zwischenergebnis ausführbarer Programmcode für eine Mehrprozessorarchitektur, beispielsweise mit drei Prozessoren, erzeugt werden. Dabei würde beispielsweise für jeden der drei Blöcke B, C und D ausführbarer Programmcode erzeugt, welcher dann parallel auf jeweils einem der drei Prozessoren ausgeführt werden könnte. In analoger Weise könnte für die Unteranteile F1, F2, ..., Fk jeweils parallel ausführbarer Programmcode für einen der drei Prozessoren erzeugt werden.
-
Ausgehend von einem derart für eine Mehrprozessorarchitektur erzeugten, ausführbaren Programmcode kann sequentiell ausführbarer Programmcode 52 für einen Datenträger 10 mit lediglich einem Prozessor erzeugt werden, wie dies in 3C illustriert ist. Dabei sind die Programmcodeanteile, welche den jeweils als nebenläufig ausführbar ermittelten Anteilen B, C und D bzw. F1, F2, ..., Fk, entsprechen, als solche gekennzeichnet worden, wie dies durch die Schraffur angedeutet ist, und anschließend für eine sequentielle Ausführung angeordnet worden. Die Kennzeichnung ist dabei derart ausgebildet, dass die Reihenfolgenfestlegungseinrichtung 56 beim Festlegen der Reihenfolge, in der die nebenläufig ausführbaren Programmcodeanteile bei einer sequentiellen Ausführung des Programmcodes 52 ausgeführt werden sollen (vgl. Schritt T2 in 3), erkennen kann, welche Anteile jeweils relativ zueinander nebenläufig ausführbar sind. Im gezeigten Beispiel sind dies die Anteile B, C, D bzw. die Unteranteile F1 bis Fk des Anteils F.
-
Aufgrund der Tatsache, dass diese Anteile parallel ausführbar sind, d. h. keine kausale Beziehung zueinander aufweisen, bleibt die Funktionalität des Gesamtprogramms identisch erhalten, egal in welcher Reihenfolge die Anteile bei einer sequentiellen Ausführung ausgeführt werden.
-
Gemäß einer zweiten Variante wird nicht erst, wie mit Bezug auf die erste Variante beschrieben, ausführbarer Programmcode für eine Mehrprozessorarchitektur erzeugt, welcher zum Erzeugen einer sequentiell ausführbaren Version erst wieder zerlegt und in beschriebener Weise gekennzeichnet und angeordnet werden muss. Alternativ erfolgt hier die Anordnung der nebenläufig ausführbaren Anteile auf einer Ebene oberhalb des Maschinencodes, beispielsweise auf der Ebene des erwähnten Zwischencodes. Ausführbarer Programmcode 52 wird dann lediglich zur sequentiellen Ausführung erzeugt, wobei die den nebenläufig ausführbaren Anteilen B, C, D bzw. F1, F2, Fk entsprechenden Programmcodeanteile erneut als solche gekennzeichnet werden, wie dies in 3C gezeigt ist.
-
Die Resultate, d. h. der erzeugte Programmcode 52, der ersten und der zweiten Variante entsprechen einander im Wesentlichen. Leichte Unterschiede können sich dadurch ergeben, dass beispielsweise Programmcode, welcher für eine echt parallele Ausführung auf einer Mehrprozessorarchitektur erzeugt worden ist, zusätzlichen Code umfasst, beispielsweise für eine mehrfache Initialisierung einzelner Variablen für jeden der parallel auszuführenden Zweige. Dieser Code ist in der direkt zur sequentiellen Ausführung erzeugten Version verzichtbar. Insofern ergibt sich ein jeweils unterschiedliches Speicherabbild. Hinsichtlich des Laufzeitverhaltens hingegen sind praktisch keine erkennbaren Unterschiede zu erwarten.
-
Grundsätzlich wird die Funktionalität zum Ermitteln nebenläufig ausführbarer Anteile durch einen entsprechend eingerichteten Compiler bereitgestellt, insbesondere durch einen Compiler, der eingerichtet ist, Programmcode zu erzeugen, welcher auf einer Mehrprozessorarchitektur echt parallel ausgeführt werden kann. Das beschriebene Verfahren zum Erzeugen des sequentiell ausführbaren, datenträgerspezifischen Programmcodes macht sich, wie beschrieben, einen solchen Compiler oder eine vergleichbare Einrichtung zunutze. Ein Erkennen von nebenläufig ausführbaren Programmcodeanteilen anhand bereits erzeugten, ausführbaren Programmcodes kann ähnliche Techniken verwenden und unabhängig von einem Übersetzungsprozess erfolgen.
-
Es kann weiter vorgesehen sein, dass alternativ oder zusätzlich, auf der Ebene des Quellcodes bereits Anteile vorgegeben werden können, welche nebenläufig ausgeführt werden können. Dies kann beispielsweise mittels geeigneter Compiler-Direktiven erfolgen, die in den Programmcode geeignet eingefügt werden, wie diese z. B. im Zusammenhang mit der Programmierschnittstelle „OpenMP” bekannt sind. Mittels solcher Direktiven kann dem Compiler beispielsweise mitgeteilt werden, dass grundsätzlich als sequentiell ausführbar vorgesehene Anteile, so genannte „sections”, z. B. die vorstehend angegebenen Anteile B, C und D, nebenläufig ausgeführt werden können. Dabei obliegt es dem Programmierer, die Bedingungen der nebenläufigen Ausführbarkeit zu überprüfen.
-
Solche „sections” können in einzelnen Fällen aber auch auf Ebene des bereits erzeugten, ausführbaren Programmcodes als nebenläufig ausführbar erkannt werden.
-
Weiter können mittels geeigneter Direktiven solche Programmcodesequenzen, von denen bekannt ist, dass deren Anweisungen in einfacher Weise parallel ausgeführt werden können, dem Compiler angezeigt werden. Besonders geeignet sind Schleifenkonstruktionen, bei denen die einzelnen Schleifendurchläufe bezüglich Ein- und Ausgabedaten unabhängig voneinander sind. Diese Situation ist in den 3A und 3B mit dem Block F und den Unteranteilen F1, F2, ..., Fk angedeutet. Der Block F könnte beispielsweise die Schleife (for i = 0; i < k; i++){f[i] := 2·i + 1} umfassen. Mittels einer Compilerdirektive wird der Compiler angewiesen, die Schleife zu parallelisieren. Dieser erkennt, dass die einzelnen Schleifendurchläufe unabhängig voneinander sind und erzeugt entsprechend k nebenläufig ausführbare Unteranteile F1, F2, ..., Fk.
-
In einzelnen Fällen ist es aber auch möglich, Schleifenstrukturen und ähnliche Konstrukte auf der Ebene des ausführbaren Programmcodes zu erkennen und in die entsprechenden nebenläufig ausführbaren Programmcodeanteile zu zerlegen.
-
Es kann vorteilhaft sein, im Schritt des Ermitteln von nebenläufig ausführbaren Anteilen eine Anzahl von gleichzeitig nebenläufig ausführbaren Anteilen vorzugeben. Im vorhergehenden Beispiel hätte somit auch mit Bezug auf den Block F die Anzahl der Unteranteile beschränkt werden können.
-
Wie bereits erwähnt, können ein oder mehrere der als nebenläufig ausführbar ermittelten Anteile hinsichtlich eines oder mehrerer Parameter optimiert werden. Bekannte Compiler verfügen dazu in der Regel über entsprechende Compile-Optionen, welche es beispielsweise erlauben, in mehreren Stufen hinsichtlich Ausführungsgeschwindigkeit oder Speicherbedarf optimierten Programmcode zu erzeugen. Dadurch, dass nicht der gesamte Programmcode einheitlich optimiert wird, sondern lediglich ausgewählte Anteile, kann eine weitere datenträgerspezifische Ausgestaltung des in dieser Weise erzeugten Programmcodes 52 erreicht werden. Die Optimierung wirkt sich in der Regel sowohl auf das Laufzeitverhalten als auch auf die benötigten Speicherressourcen aus. Es können auch Optimierungsstufen gewählt werden, welche lediglich geeigneten, optimierten Zwischencode erzeugen. Ausführbarer Programmcode wird dann erst von einer Linker-Funktionalität erzeugt. Auf diese Weise kann einer Optimierung durchgeführt werden, welche nicht lediglich einzelne Module, sondern ein gesamtes Programmpaket betrifft.
-
Es versteht sich, dass die Optimierung alternativ oder zusätzlich auch auf solche Anteile A, E und G erstreckt werden kann, die nicht nebenläufig ausführbar sind.