Open Source im professionellen Einsatz

Newsletter abonnieren
Seite durchsuchen

HEFTARCHIV | NEWS | E-BIBLIOTHEK | VIDEO | BLOGS | WHITEPAPER | EVENTS | ACADEMY | ABO | SHOP

user friendly

  Home  »  Heft & Abo  »  Heftarchiv  »  2006  »  06  »  Kern-Technik  

RSS-Feed der aktuellen News von Linux-Magazin Online Folgen Sie Linux-Magazin Online auf Twitter
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark

Endianness

Doch selbst Prozessoren mit gleicher Wortbreite unterscheiden sich noch so grundlegend, dass es zu Portierungsproblemen kommt. Unterschiedliche Prozessoren legen Daten nämlich auch anders im Speicher ab. Denn unglücklicherweise gibt es gleich zwei Formate, um 16-, 32- oder 64-Bit-Wörter im Speicher zu repräsentieren.

Abbildung 3 zeigt, dass das Little-Endian-Format das niederwertige Byte eines Wortes auf die niederwertige Adresse legt. So macht es etwa der klassische PC mit x86-Prozessoren. Eine Sun-Workstation mit Sparc-Prozessor legt dagegen das niederwertige Byte an die höherwertige Adresse. Es gibt sogar Prozessoren, die beides können.


Abbildung 3: Prozessoren legen die einzelnen Bytes eines Datenwortes unterschiedlich im Speicher ab. Beim Little-Endian-Format steht das niederwertige Byte an der niederwertigen (»0«), bei Big Endian dagegen an der höherwertigen Adresse.

Der Endian-Unterschied wird dann zum Problem, wenn zwei oder mehr Prozessoren, die unterschiedliche Datenablageformate verwenden, auf denselben Datensatz zugreifen. Bei vernetzten Rechnersystemen ist das ohnehin oft der Fall. Das Problem kann aber auch beim Zugriff auf intelligente Hardware auftreten, deren Anbindung zumeist über ein Speicherinterface (Dual-Port-RAM, Shared Memory) realisiert ist. Gleiches gilt beim Speichern von Daten auf einer Festplatte - spätestens seit USB 2.0 und Firewire sind diese portabel und leicht von einem zum anderen Rechner zu transportieren.

Byte-Swapping sparen

Zur Lösung des Problems bietet Linux vom Ablageformat des Prozessors unabhängige Datentypen an: »__le16«,» __le32«, »__le64« und »__be16«, »__be32«, »__be64« (siehe Tabelle 1). Außerdem kann der Programmierer auf Makros zurückgreifen, die zwischen den Formaten konvertieren (siehe Tabelle 2).

Tabelle 2:
Funktionen zur Konvertierung zwischen
Wort-Ablageformaten

 

Erklärung

Funktionsnamen

Umwandlung aus dem Host- ins Netzwerk-Format (Big Endian)

__be16 htons( __u16 value ), __be32 htonl( __u32 value )

Umwandlung aus dem Netzwerk- (Big Endian) ins Host-Format

__u16 ntohs( __be16 value ), __132 ntohl( __be32 value );

Umwandlung aus dem Host- ins Little-Endian-Format

__le16 cpu_to_le16( __u16 value ), __le32 cpu_to_le32( __u32
value ), __le64 cpu_to_le64( __u64 value )

Umwandlung aus dem Host- ins Little-Endian-Format, das
Ergebnis

der Wandlung wird in der ursprünglichen Variablen abgelegt (in
situ)

void cpu_to_le16s( __u16 *value ), void cpu_to_le32s( __u32
*value ), void cpu_to_le64s( __u64 *value )

Umwandlung aus dem Host- ins Big-Endian-Format

__be16 cpu_to_be16( __u16 value ), __be32 cpu_to_be32( __u32
value ), __be64 cpu_to_be64( __u64 value )

Umwandlung aus dem Host- ins Big-Endian-Format, das
Ergebnis

der Wandlung wird in der ursprünglichen Variablen abgelegt (in
situ)

void cpu_to_be16s( __u16 *value ), void cpu_to_be32s( __u32
*value ),

void cpu_to_be64s( __u64 *value )

Umwandlung einer Little-Endian-Variablen ins Host-Format

__u16 le_to_cpu16( __le16 value ), __u32 le_to_cpu32( __le32
value ), __u64 le_to_cpu64( __le64 value )

Umwandlung einer Little-Endian-Variablen ins Host-Format, das
Ergebnis

wird in der Variablen selbst abgelegt (in situ)

void le_to_cpu16s( __le16 *value ), void le_to_cpu32s( __le32
*value ),

void le_to_cpu64s( __le64 *value )

Umwandlung einer Big-Endian-Variablen ins Host-Format

__u16 be_to_cpu16( __be16 value ), __u32 be_to_cpu32( __be32
value ), __u64 be_to_cpu64( __be64 value )

Umwandlung einer Big-Endian-Variablen ins Host-Format, das
Ergebnis

wird in der Variablen selbst abgelegt (in situ)

void be_to_cpu16s( __be16 *value ), void be_to_cpu32s( __be32
*value ),

void be_to_cpu64s( __be64 *value )

Damit bei dieser Umwandlung nicht bereits vorher feststehen muss, ob der verwendete Prozessor ein Little- oder ein Big-Endian-Format unterstützt, wandeln sie immer in das CPU- oder Host-Format respektive aus dem CPU- oder dem Host-Format. Dabei ist natürlich berücksichtigt, ob die CPU selbst das Zielformat unterstützt. Dann wird beim Kompilieren der Wert ohne Byte-Swapping übernommen (siehe »__cpu_to_le32(x)« in Listing 2 , Zeile 2).

Listing 2:
»linux/byteorder/little_endian.h«

01 ...
02 #define __cpu_to_le32(x) ((__u32)(x))
03 #define __le32_to_cpu(x) ((__u32)(x))
04 #define __cpu_to_le16(x) ((__u16)(x))
05 #define __le16_to_cpu(x) ((__u16)(x))
06 #define __cpu_to_be64(x) __swab64((x))
07 #define __be64_to_cpu(x) __swab64((x))
08 #define __cpu_to_be32(x) __swab32((x))
09 #define __be32_to_cpu(x) __swab32((x))
10 ...

Die Makros, die im Netzwerkbereich zum Einsatz kommen, heißen: »htons()« (host to network short), »htonl()« (host to network long), »ntohs()« (network to host short) und »ntohl()« (network to host long). Ein Makro »htonc()« (host to char) gibt es nicht, denn das Problem tritt nur bei Variablen auf, die 16, 32 oder 64 Bit umfassen. Der Name Htonl ist übrigens irreführend: Diese Funktion wandelt das Host-Format in ein 32-Bit-Wort (Integer). Wäre es wirklich ein »long«, käme es zu Problemen mit allen 64-Bit-Maschinen. Das Netzwerkformat ist traditionell vom Typ Big Endian. Auf dem x86-PC müssen daher alle Wörter in den Protokollheadern gedreht werden. Eine Sun-Workstation mit Sparc-Prozessor kann darauf verzichten.

Außerhalb der Netzwerkprogrammierung benutzt der Linux-Kernel die Makros »cpu_to_leX()«, »cpu_to_leXs()«, »cpu_to_beX()« und »cpu_to_beXs()« (siehe Tabelle 2), die auch 64 Bit breite Variablen unterstützen. Das angehängte »s« bei einigen der Makros steht für "in situ". Diese Makros wandeln direkt die Variable selbst. Deshalb besitzen sie keinen Rückgabewert und bekommen nicht eine Kopie, sondern die Adresse der Variablen übergeben.

Das Makro »htons()« entspricht damit der Funktion »cpu_to_be16()«, »htonl()« entspricht »cpu_to_be32()«. Wie man mit Hilfe der Datentypen und Makros programmiert, demonstriert der Kernelcode, der das Ext-2-Filesystem realisiert. Einen Ausschnitt daraus zeigt Listing 3.

Listing 3: Ausschnitt aus
»linux/ext2_fs.h«

01 ...
02 struct ext2_super_block {
03         __le32  s_inodes_count;         /* Inodes count */
04         __le32  s_blocks_count;         /* Blocks count */
05         __le32  s_r_blocks_count;       /* Reserved blocks count */
06         __le32  s_free_blocks_count;    /* Free blocks count */
07         __le32  s_free_inodes_count;    /* Free inodes count */
08         __le32  s_first_data_block;     /* First Data Block */
09         __le32  s_log_block_size;       /* Block size */
10         __le32  s_log_frag_size;        /* Fragment size */
11         __le32  s_blocks_per_group;     /* # Blocks per group */
12         __le32  s_frags_per_group;      /* # Fragments per group */
13         __le32  s_inodes_per_group;     /* # Inodes per group */
14         __le32  s_mtime;                /* Mount time */
15         __le32  s_wtime;                /* Write time */
16         __le16  s_mnt_count;            /* Mount count */
17         __le16  s_state;                /* File system state */
18 ...
19 #define EXT2_HAS_COMPAT_FEATURE(sb,mask)                        
20         ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
21 #define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                     
22         ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
23 ...
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark
Ähnliche Artikel
Kern-Technik Kernel- und Treiberprogrammierung mit dem Kernel 2.6 - Folge 43
Handliche Bibliotheken Optimale C-Bibliotheken für Embedded Linux
Exotische Architekturen Linux portieren
Kern-Technik Kernel- und Treiberprogrammierung mit dem Kernel 2.6 -
Zwillingsforschung Technik, Marktübersicht und Grundlagen zu Mehrkern-Prozessoren
Völlig losgelöst Binaries auf fremder Architektur mit Quicktransit
Whitepaper
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele

Über die letzten Jahre hinweg haben sich Open Source Lösungen als fester Bestandteil des gesamten Datenintegrationsmarktes etabliert. Viele Unternehmen haben bereits das Open Source Modell für Ihre Datenintegrationsprojekte aufgegriffen. Das vorliegende White Paper illustriert anhand ausgewählter Fallstudien und Anwendungsbeispiele die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.

Download PDF (Registrierung erforderlich)
The Role of Open Source in Data Integration

Obwohl in den letzten Jahren viele technische Fortschritte erzielt werden konnten, verfügen die meisten Datenintegrationsprozesse nach wie vor nur über eine sehr begrenzte Automatisierung. Das vorliegende White Paper von dem Industry Analyst Mark Madson wird zunächst ein grundlegendes Verständnis von Daten Integration vermitteln, die Vorzüge von Open Source Lösungen für Daten Integration erläutern und Ihnen professionelle Empfehlungen geben, damit Sie Ihre Integrationsjobs noch einfacher und produktiver gestalten können.

Download PDF (Registrierung erforderlich)
Kommentare (0)