ll_entry_declare() 在 U-Boot 中如何工作?

How ll_entry_declare() works in U-Boot?

当 U-boot shell 想要从 linker_list 中查找命令时,它会调用以下函数 -

cmd_tbl_t *find_cmd(const char *cmd)
{
         cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);
         const int len = ll_entry_count(cmd_tbl_t, cmd);
         return find_cmd_tbl(cmd, start, len);
}

要获取指向包含此命令所有细节的结构 cmd_tbl_t 的指针,将调用 ll_entry_start()。

#define ll_entry_start(_type, _list)                                    
 ({                                                                      
         static char start[0] __aligned(4) __attribute__((unused,        
                 section(".u_boot_list_2_"#_list"_1")));                 
         (_type *)&start;                                                
 })

ll_entry_start 返回指向保存命令的结构 cmd_tbl_t 开始的指针。

我们无法预测传递给 find_cmd() 的字符串是什么。

#(stringizing) 运算符是预处理器指令。它无法在运行时从令牌名称生成字符串。编译器如何为 _list 可以接受的所有可能的字符串值生成代码?

链接器生成的命令列表通过使用 U_BOOT_CMD 宏指定命令来填充。这是来自 cmd/bootefi.c

的示例
U_BOOT_CMD(
        bootefi, 3, 0, do_bootefi,
        "Boots an EFI payload from memory",
        bootefi_help_text
);

链接器在 u-boot 二进制文件中为每个命令创建一个部分,例如对于 bootefi:.u_boot_list_2_cmd_2_bootefi

您可以使用 ll_entry_start 和 ll_entry_next 迭代链接器生成的列表。以下是取自 lib/efi_selftest/efi_selftest.c:

的示例
for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
     test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
        efi_st_printf("'%s'%s\n", test->name,
                      test->on_request ? " - on request" : "");
}