2010-03-30 35 views
42

Tôi muốn biên dịch mã C của mình mà không có (g) libc. Làm thế nào tôi có thể tắt nó và các chức năng phụ thuộc vào nó?Biên dịch không có libc

Tôi đã cố gắng -nostdlib nhưng nó không giúp: Mã được biên dịch và chạy, nhưng tôi vẫn có thể tìm thấy tên của libc trong hexdump của tệp thực thi của tôi.

+1

'-nostdlib' nên làm điều đó, những phiên bản nền tảng/biên dịch bạn đang sử dụng? –

+0

"không giúp" như trong đó đã không vô hiệu hóa các thư viện, hoặc bạn không thể biên dịch bất cứ điều gì với lá cờ đó? –

+3

Bạn cũng có thể muốn -nostartupfiles. –

Trả lời

53

Nếu bạn biên dịch mã bằng -nostdlib, bạn sẽ không thể gọi bất kỳ chức năng thư viện C nào (tất nhiên), nhưng bạn cũng không nhận được mã khởi động C thông thường. Đặc biệt, điểm vào thực của một chương trình trên Linux không phải là main(), mà là một hàm có tên _start(). Các thư viện chuẩn thường cung cấp một phiên bản này chạy một số mã khởi tạo, sau đó gọi hàm main().

Cố gắng biên soạn này với -nostdlib gcc:

void _start() { 

    /* main body of program: call main(), etc */ 

    /* exit system call */ 
    asm("movl $1,%eax;" 
     "xorl %ebx,%ebx;" 
     "int $0x80" 
    ); 
} 

Các _start() chức năng nên luôn luôn kết thúc với một cuộc gọi để thoát (hoặc cuộc gọi hệ thống không trở khác như exec). Ví dụ trên gọi trực tiếp hệ thống gọi với lắp ráp nội tuyến vì lối ra thông thường() không có sẵn.

+3

Đối với 64 bit, mã assembly phải giống như sau: 'asm (" mov rax, 60; mov rdi, 0; syscall ")'. – sigalor

+3

Thêm vào nhận xét của @ sigalor, để biên dịch với 'gcc', bạn sẽ cần phải sử dụng cú pháp AT & T vì thế nó sẽ giống như sau:' asm (mov $ 60,% rax; mov $ 0,% rdi; syscall) ' – lanoxx

+0

@ataylor: tại sao hàm _start() luôn luôn kết thúc bằng lời gọi để thoát()? Điều gì sẽ xảy ra nếu tôi không viết exit() trong hàm start()? – Destructor

6

Cách đơn giản nhất là biên dịch mã C thành tệp đối tượng (gcc -c để nhận một số tệp *.o) và sau đó liên kết trực tiếp với trình liên kết (ld). Bạn sẽ phải liên kết các tệp đối tượng của bạn với một vài tệp đối tượng bổ sung chẳng hạn như /usr/lib/crt1.o để có được tệp thực thi hoạt động (giữa điểm vào, như hạt nhân nhìn thấy và chức năng main(), có một số công việc cần làm) . Để biết những gì để liên kết với, hãy thử liên kết với glibc, sử dụng gcc -v: điều này sẽ cho bạn thấy những gì thường đi vào thực thi.

Bạn sẽ thấy rằng gcc tạo mã có thể có một số phụ thuộc vào một vài hàm ẩn. Hầu hết trong số họ là trong libgcc.a. Cũng có thể có các cuộc gọi ẩn tới memcpy(), memmove(), memset()memcmp(), nằm trong libc, vì vậy bạn có thể phải cung cấp các phiên bản của riêng bạn (không khó, ít nhất là bạn không quá cầu kỳ về hiệu suất).

Mọi thứ có thể sẽ rõ ràng hơn nếu bạn nhìn vào cụm được sản xuất (sử dụng cờ -S).

+0

Tôi phải sử dụng _start thay vì chính, nhưng khi tôi cố gắng gọi một chức năng libc gcc không phàn nàn. Liên kết libc có biến mất nếu tôi xóa tất cả các cuộc gọi libc không? – dkreuter

+2

Không trực tiếp. Nếu bạn thử 'gcc -v', bạn sẽ thấy' gcc' cung cấp một số tệp đối tượng cho trình liên kết ('* .o'). Trình liên kết bao gồm tất cả các tệp đối tượng được cung cấp. "Disappearance" chỉ xảy ra với các thư viện ('*.a') bởi vì chúng là kho lưu trữ của các tệp đối tượng mà trình liên kết là miễn phí để sử dụng hoặc không sử dụng. –

20

http://blog.ksplice.com/2010/03/libc-free-world/ có mô tả rất tốt về kiểm soát chính xác đầu ra chương trình của gcc.

Chỉnh sửa: Họ (ksplice) vừa đưa ra phần 2 của hướng dẫn/hướng dẫn ở trên. Xem nó ở đây: http://blog.ksplice.com/2010/04/libc-free-world-2/ Điều này chủ yếu là giao dịch với các thiết lập liên kết để loại bỏ fluff không cần thiết từ các tập tin.

+0

+1, liên kết rất thông tin. –

+0

Tôi tự hỏi đâu là phần 3 – navigaid

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