你所不知道的c
十二月 20, 2023你所不知道的c
嵌入一個二進位檔案到執行檔
xxd --include blob
uname -a > blob
uname -a | wc -c
# 105
ld -s -r -b binary -o blob.o blob
objdump -t blob.o
cat > /tmp/t.c <<EOF
#include <stdio.h>
int main() {
extern void *_binary_blob_start, *_binary_blob_end;
void *start = &_binary_blob_start, *end = &_binary_blob_end;
printf("Data: %p..%p (%zu bytes)\n",
start, end, end-start);
return 0;
}
EOF
gcc /tmp/t.c blob.o -o test
./test
# Data: 0x55ed5ed15010..0x55ed5ed15079 (105 bytes)
readelf -S blob.o
objcopy to carry
cat > testme.c <<EOF
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
extern void _binary__etc_passwd_size;
extern char _binary__etc_passwd_start;
extern char _binary__etc_passwd_end;
int
main(int argc, char **argv)
{
(void)argc;
(void)argv;
/* try one of the following two lines */
// size_t size = &_binary__etc_passwd_size;
size_t size = &_binary__etc_passwd_end - &_binary__etc_passwd_start;
printf("Dumping /etc/passwd, in memory @%p, size is %zu.\n",
&_binary__etc_passwd_start, size);
write(1,&_binary__etc_passwd_start,size);
exit(0);
}
EOF
cat >Makefile <<EOF
CFLAGS=-Wall -Wextra -ggdb -Os
all : testme
testme : testme.o passwd.o
###
# To learn about the correct architecture and file formats,
# run objdump -x on a file compiled for your architecture of choice!
###
ifeq ($(shell uname -m),x86_64)
OBJCOPY_ARCH=-O elf64-x86-64 -B i386:x86-64
else ifeq ($(shell uname -m),armv6l)
OBJCOPY_ARCH=-O elf32-littlearm -B arm
else
OBJCOPY_ARCH=UNKNOWN_ARCHITECTURE_EDIT_MAKEFILE_TO_FIX_THIS
endif
passwd.o : /etc/passwd
objcopy -I binary $(OBJCOPY_ARCH) \
--rename-section .data=.rodata,alloc,load,readonly,data,contents \
--add-section ".note.GNU-stack"=/dev/null \
--set-section-flags ".note.GNU-stack"=contents,readonly \
$< $@ || (rm -f $@ ; exit 1)
.PHONY : clean
clean :
rm -f *.o passwd.* testme *.d *~
EOF
init script 示範
cat > demo.c <<EOF
#include <init_hook.h>
#include <debug.h>
#define INIT_HOOK(_hook, _level) \
const init_struct _init_struct_##_hook \
__attribute__((section(".init_hook"))) = { \
.level = _level, \
.hook = _hook, \
.hook_name = #_hook, \
};
void hook_test(void) {
dbg_printf(DL_EMERG, "hook test\n");
}
INIT_HOOK(hook_test, INIT_LEVEL_PLATFORM - 1)
EOF
在 platform/stm32f4/f9.ld 配置了 .init_hook 的空間:
init_hook_start = .;
KEEP(*(.init_hook))
init_hook_end = .;
最後在 kernel/init.c 就清晰了:
extern const init_struct init_hook_start[];
extern const init_struct init_hook_end[];
static unsigned int last_level = 0;
int run_init_hook(unsigned int level) {
unsigned int max_called_level = last_level;
for (const init_struct *ptr = init_hook_start;
ptr != init_hook_end; ++ptr)
if ((ptr->level > last_level) &&
(ptr->level <= level)) {
max_called_level = MAX(max_called_level, ptr->level);
ptr->hook();
}
last_level = max_called_level;
return last_level;
}