2012-04-26 33 views
8

Tôi đang viết một bộ phân tích ELF, nhưng tôi đang gặp một số vấn đề khi chuyển đổi độ chính xác. Tôi có các chức năng để xác định endianness của máy phân tích và endiannness của tập tin đối tượng.Hoán đổi độ tin cậy mà không cần ntohs

Về cơ bản, có bốn kịch bản có thể:

  1. Một endian biên soạn lớn phân tích chạy trên một tập tin đối tượng về cuối lớn
    • nhu cầu không có gì chuyển
  2. Một endian biên soạn lớn phân tích chạy trên một tệp đối tượng cuối cùng nhỏ
    • thứ tự byte cần đổi chỗ, nhưng ntohs/l() và htons/l() đều là các macro trống o n một máy cuối lớn, vì vậy chúng sẽ không trao đổi thứ tự byte. Đây là vấn đề
  3. Một endian biên soạn ít phân tích chạy trên một tập tin đối tượng về cuối lớn
    • nhu cầu thứ tự byte hoán đổi, vì vậy sử dụng htons() để trao đổi thứ tự byte
  4. Một máy phân tích biên dịch cuối cùng nhỏ chạy trên một tệp đối tượng cuối cùng nhỏ.
    • nhu cầu không có gì chuyển

Có một chức năng tôi có thể sử dụng để dứt khoát trao đổi byte thứ tự/thay đổi endianness, vì ntohs/l() và htons/l() lấy endianness của máy chủ vào tài khoản và đôi khi không chuyển đổi? Hoặc tôi có cần tìm/ghi hàm thứ tự byte hoán đổi của riêng mình không?

Trả lời

3

Tôi có cần phải tìm/ghi chức năng hoán đổi thứ tự byte của riêng tôi?

Có bạn đã làm. Tuy nhiên, để làm cho nó dễ dàng, tôi giới thiệu bạn đến câu hỏi này: How do I convert between big-endian and little-endian values in C++? cung cấp danh sách các hàm hoán đổi thứ tự byte cụ thể của trình biên dịch, cũng như một số triển khai các hàm hoán đổi thứ tự byte.

7

Trong Linux there are several conversion functions trong endian.h, cho phép để chuyển đổi giữa endianness tùy ý:

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

Edited, giải pháp ít đáng tin cậy. Bạn có thể sử dụng union để truy cập các byte theo thứ tự bất kỳ. Đó là khá thuận tiện:

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

Hành vi không xác định về mặt kỹ thuật trong C++. – bames53

+0

Nhưng làm thế nào để chúng ta biết đúng thứ tự? –

+0

@BoPersson OP biết, khi anh ta muốn trao đổi byte. Tôi đã chỉnh sửa câu trả lời của mình để hiển thị giải pháp phù hợp hơn. –

1

Các chức năng ntoh có thể trao đổi giữa nhiều hơn chỉ lớn và nhỏ về cuối. Một số hệ thống cũng là 'trung endian', nơi các byte được tranh giành thay vì chỉ được đặt hàng theo cách này hay cách khác.

Dù sao, nếu tất cả những gì bạn quan tâm là lớn và nhỏ về cuối, thì tất cả những gì bạn cần biết là nếu máy chủ lưu trữ và tệp cuối cùng của tệp đối tượng khác nhau. Bạn sẽ có chức năng của riêng bạn mà hoán đổi thứ tự byte vô điều kiện và bạn sẽ gọi nó hoặc không dựa trên việc có hay không host_endianess()==objectfile_endianess().

0

Nếu tôi sẽ suy nghĩ về một giải pháp đa nền tảng đó sẽ làm việc trên cửa sổ hoặc linux, tôi sẽ viết một cái gì đó như:

#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

Tôi nghĩ rằng nó có giá trị nâng cao The Byte Order Fallacy bài viết ở đây, bởi Rob Pyke (một trong Tác giả của Go).

Nếu bạn làm điều đúng - nghĩa là bạn không giả định bất kỳ thứ gì về thứ tự byte nền tảng của bạn - thì nó sẽ hoạt động. Tất cả những gì bạn cần quan tâm là liệu các tệp định dạng ELF có ở chế độ Little Endian hoặc Big Endian.

Từ bài viết:

Hãy nói rằng dòng dữ liệu của bạn có một số nguyên 32-bit ít về cuối nhỏ-mã hóa. Dưới đây là làm thế nào để giải nén nó (giả sử byte unsigned):

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

Nếu đó là lớn về cuối nhỏ, dưới đây là cách để giải nén nó:

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

Và hãy để những lo lắng biên dịch về tối ưu hóa heck ra khỏi nó.

+0

Trình biên dịch AFAIK sẽ chỉ sử dụng trao đổi thứ tự byte được tối ưu hóa nếu bạn bắt đầu bằng một từ ở vị trí đầu tiên. –

+0

@AndrewDunn: Khá có thể, nhưng như thường lệ, đo hai lần, tối ưu hóa một lần. –

Các vấn đề liên quan