多重引导规范的结构如下所示:
struct multiboot_tag_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t entry_size;
multiboot_uint32_t entry_version;
struct multiboot_mmap_entry entries[0];
};其意图似乎是数组大小可以改变。在引导加载程序传递信息之前,不知道这些信息。在托管C++中,建议的建议是“使用vector”。我不能那么做。另一种方法是使用动态分配,但这需要实现内核的一个重要部分(分页、MMU等)。在我还没有记忆地图信息之前。有点鸡或蛋的问题。
"hack“只是使用gnu++11启用扩展。但我尽量避免使用扩展,以避免可能导致未定义行为的C代码或代码。在我看来,代码的可移植性越强,出现bug的可能性就越小。
最后,您可以像下面这样迭代内存映射:
for (mmap = ((struct multiboot_tag_mmap *) tag)->entries;
(multiboot_uint8_t *) mmap
< (multiboot_uint8_t *) tag + tag->size;
mmap = (multiboot_memory_map_t *)
((unsigned long) mmap
+ ((struct multiboot_tag_mmap *) tag)->entry_size))所以这个结构的大小是tag->size。
只要语义相同,我就可以修改多重引导头。重点在于引导加载器的外观。我能做什么?
发布于 2015-11-02 07:02:54
您可以使用1大小的数组,而不是0大小的数组:
struct multiboot_tag_mmap
{
...
struct multiboot_mmap_entry entries[1];
};这只会改变sizeof(struct multiboot_tag_mmap)的结果,但无论如何都不应该使用:分配的结构的大小应该计算为
offsetof(struct multiboot_tag_mmap, entries) + <num-of-entries> * sizeof(struct multiboot_mmap_entry)映射结构的对齐不取决于条目数组中的元素数量,而取决于条目类型。
严格确认可选的:如果存在数组大小的已知边界,则可以使用此边界进行类型声明:
struct multiboot_tag_mmap
{
...
struct multiboot_mmap_entry entries[<UPPER-BOUNDARY>];
};对于这种声明,不适用下文所述的所有可能问题。
关于元素访问的注释:用于访问这种灵活数组中的元素(在第一个元素之上)的,需要声明新的指针变量:
struct multiboot_mmap_entry* entries = tag->entries;
entries[index] = ...; // This is OK.而不是直接使用entries字段:
tag->entries[index] = ...; // WRONG! May spuriously fail!问题是,编译器知道entries字段数组中只有一个元素,所以可以将最后一种情况优化为:
tag->entries[0] = ...; // Compiler is in its rights to assume index to have the only allowed value问题有关标准确认:使用灵活的数组方法,内存中(堆或堆栈中)没有struct multiboot_tag_mmap类型的对象。我们所拥有的只是一个这种类型的指针,它永远不会被取消引用(例如,用于创建对象的完整副本)。类似地,没有数组类型struct multiboot_mmap_entry[1]的对象,该对象对应于结构的entries字段,该字段仅用于转换为struct multiboot_mmap_entry*类型的泛型指针。
所以,C标准中的短语,表示未定义的行为
对象被赋值给不完全重叠的对象或完全重叠的不兼容类型的对象。
不适用于使用泛型指针访问entries数组字段:此处不存在重叠对象。
https://stackoverflow.com/questions/33470473
复制相似问题