Từ http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 :
Gần đây tôi có nhu cầu nhúng tệp vào tệp thực thi. Vì tôi đang làm việc với dòng lệnh với gcc, et al chứ không phải với một công cụ RAD ưa thích khiến tất cả diễn ra một cách kỳ diệu nên tôi không rõ ràng là làm thế nào để biến điều này thành hiện thực. Một chút tìm kiếm trên mạng đã phát hiện ra một vụ hack về cơ bản đưa nó vào cuối tệp thực thi và sau đó giải mã vị trí của nó dựa trên một loạt thông tin mà tôi không muốn biết. Có vẻ như phải có một cách tốt hơn ...
Và đây, đó là phản đối của cuộc giải cứu. objcopy chuyển đổi các tệp đối tượng hoặc tệp thực thi từ định dạng này sang định dạng khác. Một trong những định dạng mà nó hiểu là "nhị phân", về cơ bản là bất kỳ tệp nào không thuộc một trong các định dạng khác mà nó hiểu. Vì vậy, bạn có thể đã hình dung ra ý tưởng: chuyển đổi tệp mà chúng tôi muốn nhúng thành tệp đối tượng, sau đó nó có thể được liên kết đơn giản với phần còn lại của mã của chúng tôi.
Giả sử chúng ta có tên tệp data.txt mà chúng ta muốn nhúng vào tệp thực thi của mình:
# cat data.txt
Hello world
Để chuyển đổi tệp này thành tệp đối tượng mà chúng tôi có thể liên kết với chương trình của mình, chúng tôi chỉ cần sử dụng objcopy để tạo tệp ".o":
# objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 data.txt data.o
Điều này cho đối tượng biết rằng tệp đầu vào của chúng tôi ở định dạng "nhị phân", tệp đầu ra của chúng tôi phải ở định dạng "elf32-i386" (tệp đối tượng trên x86). Tùy chọn --binary-architecture cho đối tượng biết rằng tệp đầu ra có nghĩa là "chạy" trên x86. Điều này là cần thiết để ld sẽ chấp nhận tệp để liên kết với các tệp khác cho x86. Người ta sẽ nghĩ rằng việc chỉ định định dạng đầu ra là "elf32-i386" sẽ ngụ ý điều này, nhưng không phải vậy.
Bây giờ chúng ta có một tệp đối tượng, chúng ta chỉ cần đưa nó vào khi chạy trình liên kết:
# gcc main.c data.o
Khi chúng tôi chạy kết quả, chúng tôi nhận được đầu ra được cầu nguyện:
# ./a.out
Hello world
Tất nhiên, tôi chưa kể toàn bộ câu chuyện, cũng như không cho bạn xem main.c. Khi objcopy thực hiện chuyển đổi ở trên, nó sẽ thêm một số ký hiệu "trình liên kết" vào tệp đối tượng được chuyển đổi:
_binary_data_txt_start
_binary_data_txt_end
Sau khi liên kết, các ký hiệu này chỉ định điểm bắt đầu và kết thúc của tệp nhúng. Các tên ký hiệu được hình thành bằng cách viết trước mã nhị phân và thêm _start hoặc _end vào tên tệp. Nếu tên tệp chứa bất kỳ ký tự nào không hợp lệ trong tên ký hiệu, chúng sẽ được chuyển đổi thành dấu gạch dưới (ví dụ: data.txt trở thành data_txt). Nếu bạn nhận được các tên chưa được giải quyết khi liên kết bằng cách sử dụng các ký hiệu này, hãy thực hiện hexdump -C trên tệp đối tượng và xem các tên mà objcopy đã chọn ở cuối kết xuất.
Mã để thực sự sử dụng tệp nhúng bây giờ phải rõ ràng một cách hợp lý:
#include <stdio.h>
extern char _binary_data_txt_start;
extern char _binary_data_txt_end;
main()
{
char* p = &_binary_data_txt_start;
while ( p != &_binary_data_txt_end ) putchar(*p++);
}
Một điều quan trọng và tinh tế cần lưu ý là các ký hiệu được thêm vào tệp đối tượng không phải là "biến". Chúng không chứa bất kỳ dữ liệu nào, đúng hơn, địa chỉ của chúng là giá trị của chúng. Tôi khai báo chúng là kiểu char vì nó thuận tiện cho ví dụ này: dữ liệu nhúng là dữ liệu ký tự. Tuy nhiên, bạn có thể khai báo chúng dưới dạng bất kỳ thứ gì, chẳng hạn như int nếu dữ liệu là một mảng số nguyên, hoặc như struct foo_bar_t nếu dữ liệu là bất kỳ mảng thanh foo nào. Nếu dữ liệu nhúng không đồng nhất, thì char có lẽ là thuận tiện nhất: lấy địa chỉ của nó và truyền con trỏ đến kiểu thích hợp khi bạn duyệt dữ liệu.