2012-04-26 11 views
8

Sto scrivendo un analizzatore ELF, ma sto riscontrando qualche problema nel convertire correttamente endianness. Ho delle funzioni per determinare l'endianità dell'analizzatore e l'endianità del file oggetto.Endianness swap senza ntohs

Fondamentalmente, ci sono quattro possibili scenari:

  1. Un big endian compilato corsa analizzatore su un file oggetto big endian
    • ha bisogno di niente convertiti
  2. Un big endian compilato analizzatore di corsa su un file oggetto little endian
    • l'ordine dei byte deve essere scambiato, ma ntohs/l() e htons/l() sono entrambi macro nulli o n una macchina big endian, quindi non scambieranno l'ordine dei byte. Questo è il problema
  3. A little endian compilato corsa analizzatore su un file oggetto big endian
    • le esigenze di ordine di byte scambiati, in modo da utilizzare htons() per scambiare l'ordine dei byte
  4. Un analizzatore compilato little endian gira su un piccolo file di oggetti endian.
    • ha bisogno di niente convertiti

C'è una funzione che posso utilizzare in modo esplicito scambiare byte di ordine/cambio endianness, dal momento che ntohs/l() e htons/l() prendere endianness dell'host in considerazione e a volte non convertire? O devo trovare/scrivere la mia funzione di ordine dei byte di scambio?

risposta

3

Ho bisogno di trovare/scrivere il mio funzione ordine di byte di swap?

Sì. Ma, per semplificare, vi rimando a questa domanda: How do I convert between big-endian and little-endian values in C++? che fornisce un elenco di funzioni di scambio degli ordini di byte specifici del compilatore, nonché alcune implementazioni delle funzioni di scambio degli ordini di byte.

7

In Linux there are several conversion functions in endian.h, che permettono per la conversione tra endianness arbitraria:

uint16_t htobe16(uint16_t host_16bits); 
uint16_t htole16(uint16_t host_16bits); 
uint16_t be16toh(uint16_t big_endian_16bits); 
uint16_t le16toh(uint16_t little_endian_16bits); 

uint32_t htobe32(uint32_t host_32bits); 
uint32_t htole32(uint32_t host_32bits); 
uint32_t be32toh(uint32_t big_endian_32bits); 
uint32_t le32toh(uint32_t little_endian_32bits); 

uint64_t htobe64(uint64_t host_64bits); 
uint64_t htole64(uint64_t host_64bits); 
uint64_t be64toh(uint64_t big_endian_64bits); 
uint64_t le64toh(uint64_t little_endian_64bits); 

cura, soluzione meno affidabile. Puoi usare union per accedere ai byte in qualsiasi ordine. E 'molto comodo:

union { 
    short number; 
    char bytes[sizeof(number)]; 
}; 
+0

Tuttavia, un comportamento tecnicamente non definito in C++. – bames53

+0

Ma come facciamo a sapere l'ordine corretto? –

+0

@BoPersson OP sa quando vuole scambiare byte. Ho modificato la mia risposta per esporre la soluzione più adeguata. –

1

Le funzioni ntoh possono passare da qualcosa di più rispetto a big e little endian. Alcuni sistemi sono anche "middle endian" in cui i byte sono criptati anziché semplicemente ordinati in un modo o nell'altro.

In ogni caso, se tutto quello che ti interessa sono big e little endian, allora tutto ciò che devi sapere è se l'host e l'endianess del file dell'oggetto differiscono. Avrai la tua funzione che scambia incondizionatamente l'ordine dei byte e lo chiamerai o meno a seconda che lo sia o meno host_endianess()==objectfile_endianess().

0

Se ci avrei pensato una soluzione cross-platform che avrebbe funzionato su Windows o Linux, avrei scritto qualcosa di simile:

#include <algorithm> 

// dataSize is the number of bytes to convert. 
char le[dataSize];// little-endian 
char be[dataSize];// big-endian 

// Fill contents in le here... 
std::reverse_copy(le, le + dataSize, be); 
10

Penso che valga la pena sollevare The Byte Order Fallacy articolo qui, da Rob Pyke (uno dei Go's autore).

Se fai le cose per bene - ovvero tu non dare per scontato nulla sull'ordine dei byte della tua piattaforma - allora funzionerà. Tutto ciò di cui ti devi preoccupare è se i file in formato ELF sono nella modalità Little Endian o Big Endian.

Dall'articolo:

Diciamo che il vostro flusso di dati ha un intero a 32 bit little-endian-encoded. Ecco come estrarlo (supponendo byte unsigned):

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); 

Se è big-endian, ecco come estrarlo:

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24); 

e lasciare che la preoccupazione compilatore su ottimizzandone il vantaggio.

+0

I compilatori AFAIK utilizzano solo uno scambio di byte order ottimizzato se si inizia con una parola in primo luogo. –

+0

@AndrewDunn: Molto probabilmente, ma come al solito, misura due volte, ottimizza una volta. –