你所不知道的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;
}