2012-04-26 13 views
8

Piszę analizator ELF, ale mam problem z poprawną endianness prawidłowo. Mam funkcje do określenia endianness analizatora i endiannness pliku obiektu.Zamień Endianness bez ntohs

Zasadniczo istnieją cztery możliwe scenariusze:

  1. Dużym endian skompilowany analizator bieg na pliku obiektowego big endian
    • potrzebuje niczego przekształcone
  2. Dużym endian skompilowany prowadzony przez analizator na mały obiekt obiektu endianowego
    • zamieniono kolejność bajtów, ale ntohs/l() i htons/l() są zarówno zerowymi makrami n duża maszyna endianowa, więc nie zamieniają kolejności bajtów. To jest problem
  3. Trochę endian skompilowany analizator bieg na pliku obiektowego big endian
    • potrzeby kolejność bajtów zamienione, więc używaj htons(), aby zamienić kolejność bajtów
  4. Mały kompilator skompresowany na końcu endianu na małym pliku obiektu endian.
    • potrzebuje niczego przekształcone

Czy istnieje funkcja mogę używać jawnie zamienić byte order/zmień kolejność bajtów, ponieważ ntohs/l() i htons/l() podejmuje endianness gospodarza pod uwagę a czasami się nie konwertuje? Czy muszę znaleźć/napisać własną funkcję zamiany bajtów?

Odpowiedz

7

W Linuksie there are several conversion functions w endian.h, który pozwala na konwersję pomiędzy arbitralnej endianness:

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); 

edytowany, mniej niezawodne rozwiązanie. Możesz użyć union, aby uzyskać dostęp do bajtów w dowolnej kolejności. Jest to dość wygodne:

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

Technicznie niezdefiniowane zachowanie w C++. – bames53

+0

Ale skąd znamy właściwą kolejność? –

+0

@BoPersson OP wie, kiedy chce zamienić bajty. Zmieniłem moją odpowiedź, aby przedstawić bardziej odpowiednie rozwiązanie. –

1

Funkcje ntoh mogą zamienić się na więcej niż tylko duży i mały endian. Niektóre systemy są również "middle endian", gdzie bajty są kodowane, a nie tylko uporządkowane w taki czy inny sposób.

W każdym razie, jeśli wszystko, na czym ci zależy, to duży i mały endianin, to wszystko, co musisz wiedzieć, to to, czy host i plik docelowy są różne. Będziesz miał swoją własną funkcję, która bezwarunkowo zamienia kolejność bajtów, a będziesz nazywać to, czy nie, na podstawie tego, czy host_endianess()==objectfile_endianess() czy nie.

0

Jeżeli myślę o rozwiązanie cross-platform, które będą pracować na Windows lub Linux, chciałbym napisać coś takiego:

#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

myślę, że warto podniesienie The Byte Order Fallacy artykuł tutaj, Rob Pyke (jeden z Autor Go).

Jeśli robisz wszystko dobrze - tzn. Ty, , nie zakładaj niczego na temat kolejności bajtów platformy - to po prostu zadziała. Wszystko, co musisz zadbać, to czy pliki formatu ELF są w trybie Little Endian lub Big Endian.

Z artykułu:

Załóżmy, że strumień danych zawiera 32-bitową liczbę całkowitą mało endian zakodowany. Oto jak wydobyć go (zakładając unsigned bajtach):

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

Jeśli to big-endian, oto jak go wyodrębnić:

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

I tylko niech kompilator martwić zoptymalizowanie tego.

+0

Kompilatory AFAIK będą używać tylko zoptymalizowanej wymiany bajtów, jeśli zaczniesz od słowa w pierwszej kolejności. –

+0

@AndrewDunn: Całkiem możliwe, ale jak zwykle, zmierz dwa razy, zoptymalizuj raz. –