Tôi sẽ bắt đầu với câu hỏi cuối cùng: Trong C với gcc, có thể lấy (các) giá trị của __func__
(hoặc tương đương, __FUNCTION__
) được lưu trữ trong một phần khác không phải là .rodata
(hoặc bất cứ nơi nào -mrodata=
điểm) hoặc tiểu mục đó?Buộc một số biến nhất định của trình biên dịch thành các phần ELF cụ thể (với gcc)
Lời giải thích đầy đủ:
Nói rằng tôi có một macro logging:
#define LOG(fmt, ...) log_internal(__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
(Chuỗi nối hành ##
sử dụng trong bối cảnh unary tiêu thụ dấu phẩy trước khi và chỉ khi danh sách __VA_ARGS__
trống , do đó cho phép sử dụng chuỗi định dạng có hoặc không có đối số.)
Tôi có thể sử dụng macro bình thường:
void my_function(void) {
LOG("foo!");
LOG("bar: %p", &bar);
}
có thể in (rõ ràng tùy thuộc vào việc thực hiện các log_internal
):
foo.c:201(my_function) foo!
foo.c:202(my_function) bar: 0x12345678
Trong trường hợp này, chuỗi định dạng ("foo"
và "bar: %p"
) và chuỗi preprocessor ("foo.c"
và "my_function"
) là vô danh chỉ đọc dữ liệu và chúng được đặt tự động vào mục .rodata
. Nhưng tôi muốn họ đi đến một nơi khác (tôi đang ở trên một nền tảng nhúng chạy gần như tất cả mọi thứ từ RAM cho tốc độ, nhưng hạn chế bộ nhớ đang đẩy để di chuyển một số thứ vào ROM). Đó là "dễ" để chuyển __FILE__
và chuỗi định dạng:
#define ROM_STR(str) (__extension__({static const __attribute__((__section__(".rom_data"))) char __c[] = (str); (const char *)&__c;}))
#define LOG(fmt, ...) log_internal(ROM_STR(__FILE__), __LINE__, __func__, ROM_STR(fmt), ##__VA_ARGS__)
Bạn không thể đặt một __attribute__
trên một chuỗi vô danh, vì vậy ROM_STR
vĩ mô mang lại cho nó một cái tên thoáng qua, sẽ gắn nó vào một phần cụ thể, sau đó đánh giá lại đến địa chỉ bắt đầu, vì vậy nó có thể thay thế sạch sẽ. Điều này không hiệu quả nếu bạn cố chuyển một biến số char *
thành LOG
làm chuỗi định dạng của bạn, nhưng tôi sẵn sàng loại trừ trường hợp sử dụng đó.
Thông thường, các chuỗi vô danh xảy ra giống hệt nhau được trình biên dịch kết hợp thành một vị trí lưu trữ duy nhất, vì vậy mỗi phiên bản __FILE__
trong một tệp sẽ chia sẻ cùng một địa chỉ thời gian chạy. Với cách đặt tên rõ ràng trong ROM_STR
, mỗi trường hợp sẽ nhận được vị trí lưu trữ riêng của mình, vì vậy có thể không thực sự hợp lý khi sử dụng nó trên __FILE__
.
Tuy nhiên, tôi muốn sử dụng nó trên __func__
. Vấn đề là __func__
không phải là cùng một loại ma thuật như __FILE__
. Từ hướng dẫn gcc, "Chức năng Names như Strings":
Từ định danh
__func__
được ngầm tuyên bố của người dịch như thể, ngay sau khi mở đôi của mỗi định nghĩa hàm, khai báo
static const char __func__[] = "function-name";
xuất hiện, trong đó hàm-tên là tên của hàm lexically-enclosing. Tên này là tên chưa được sắp xếp của hàm. ... Các số nhận dạng này không phải là các macro tiền xử lý. Trong GCC 3.3 và trước đó, và chỉ trong C,
__FUNCTION__
và__PRETTY_FUNCTION__
được coi là chuỗi ký tự; chúng có thể được sử dụng để khởi tạo các mảng char, và chúng có thể được nối với các chuỗi ký tự khác. GCC 3.4 và sau đó coi chúng là các biến, như__func__
.
Vì vậy, nếu bạn quấn __func__
với ROM_STR
, bạn sẽ có được
error: invalid initializer
và nếu bạn cố gắng đặt một thuộc tính phần trước hoặc sau khi sử dụng __func__
, bạn sẽ có được
error: expected expression before ‘__attribute__’
hoặc
error: expected ‘)’ before ‘__attribute__’
Và do đó chúng tôi lặp lại câu hỏi mở đầu: Có thể lấy __func__
được lưu trữ trong một phần lựa chọn của tôi không? Có lẽ tôi có thể sử dụng -fdata-sections
và thực hiện một số ma thuật tập lệnh liên kết để nhận được .rodata.__func__.*
bị loại trừ khỏi phần còn lại của .rodata
? Nếu vậy, cú pháp cho globbing với loại trừ trong một kịch bản linker là gì? Nói cách khác, một nơi nào đó bạn có một *(.rodata*)
- Tôi có thể đặt một ở một nơi khác, nhưng tôi sẽ cần phải sửa đổi glob ban đầu để loại trừ nó vì vậy tôi không nhận được hai bản sao.
Dưới đây là cú pháp [tham chiếu đến cú pháp của trình liên kết hữu ích] (http://www.xgc.com/manuals/gcc-1750-ug/p5node10.html) –
Tính đến năm 2015, gcc không còn thực hiện việc này nữa. Xem: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=192 –