未定义对 C 宏的引用,但在我定义它时出现重新定义的错误
Undefined reference to C Macro, but gets redefined error when I define it
我在 kthread.h 定义了一个宏,如下所示。
#define KERNEL_THREAD_SAVED_KERENL_TOP_OFFSET 208
我正尝试在 syscall.cc
使用该宏
#include "syscall.h"
#include "kthread.h"
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
"movq " #offset "(%%" #reg "), %%rsp \n"
// .. and in some function
void func() {
asm volatile(
SET_KERNEL_THREAD_TOP_OFFSET(KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET, rbx)
:::);
}
如果我编译它,它会给出以下链接器错误。
syscall.cc:41: undefined reference to `KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET'
好的,我明白了。所以可能链接器没有找到宏?所以我也尝试在 .cc 中用一些不同的值来定义它。
#include "syscall.h"
#include "kthread.h"
#define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 100
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
"movq " #offset "(%%" #reg "), %%rsp \n"
然后,我得到一个编译器错误
./kernel/syscall.cc:5: error: "KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET" redefined [-Werror]
5 | #define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 100
|
In file included from ./kernel/syscall.cc:3:
./kernel/kthread.h:7: note: this is the location of the previous definition
7 | #define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 208
|
很明显,编译器知道 syscall.cc 中的 KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET。那为什么链接器看不到定义??
链接器没有业务查找宏。宏由预处理器处理,它在链接器之前运行很长时间。如果链接器抱怨未定义的引用,则意味着您的宏扩展出错了。它在不应该发出的地方发出 KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET
。
问题在于
SET_KERNEL_THREAD_TOP_OFFSET(KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET, rbx)
这将扩展到
"movq " "KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET" "(%%" "rbx" "), %%rsp \n"
而您希望它扩展为(使用 kthread.h
中的值)
"movq " "208" "(%%" "rbx" "), %%rsp \n"
发生这种情况的原因是如何处理像宏这样的函数的参数。在字符串化运算符 #
.
中使用时,它们不会进行中间扩展
您可以通过引入一个间接层来解决这个问题。
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
SET_KERNEL_THREAD_TOP_OFFSET_(offset, reg)
#define SET_KERNEL_THREAD_TOP_OFFSET_(offset, reg) \
"movq " #offset "(%%" #reg "), %%rsp \n"
现在,当您尝试进行扩展时,它会分多次扩展。先到
SET_KERNEL_THREAD_TOP_OFFSET_(208, rbx)
(rbx
不是宏名,所以保持不变)。然后变成
"movq " "208" "(%%" "rbx" "), %%rsp \n"
我在 kthread.h 定义了一个宏,如下所示。
#define KERNEL_THREAD_SAVED_KERENL_TOP_OFFSET 208
我正尝试在 syscall.cc
使用该宏#include "syscall.h"
#include "kthread.h"
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
"movq " #offset "(%%" #reg "), %%rsp \n"
// .. and in some function
void func() {
asm volatile(
SET_KERNEL_THREAD_TOP_OFFSET(KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET, rbx)
:::);
}
如果我编译它,它会给出以下链接器错误。
syscall.cc:41: undefined reference to `KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET'
好的,我明白了。所以可能链接器没有找到宏?所以我也尝试在 .cc 中用一些不同的值来定义它。
#include "syscall.h"
#include "kthread.h"
#define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 100
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
"movq " #offset "(%%" #reg "), %%rsp \n"
然后,我得到一个编译器错误
./kernel/syscall.cc:5: error: "KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET" redefined [-Werror]
5 | #define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 100
|
In file included from ./kernel/syscall.cc:3:
./kernel/kthread.h:7: note: this is the location of the previous definition
7 | #define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 208
|
很明显,编译器知道 syscall.cc 中的 KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET。那为什么链接器看不到定义??
链接器没有业务查找宏。宏由预处理器处理,它在链接器之前运行很长时间。如果链接器抱怨未定义的引用,则意味着您的宏扩展出错了。它在不应该发出的地方发出 KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET
。
问题在于
SET_KERNEL_THREAD_TOP_OFFSET(KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET, rbx)
这将扩展到
"movq " "KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET" "(%%" "rbx" "), %%rsp \n"
而您希望它扩展为(使用 kthread.h
中的值)
"movq " "208" "(%%" "rbx" "), %%rsp \n"
发生这种情况的原因是如何处理像宏这样的函数的参数。在字符串化运算符 #
.
您可以通过引入一个间接层来解决这个问题。
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
SET_KERNEL_THREAD_TOP_OFFSET_(offset, reg)
#define SET_KERNEL_THREAD_TOP_OFFSET_(offset, reg) \
"movq " #offset "(%%" #reg "), %%rsp \n"
现在,当您尝试进行扩展时,它会分多次扩展。先到
SET_KERNEL_THREAD_TOP_OFFSET_(208, rbx)
(rbx
不是宏名,所以保持不变)。然后变成
"movq " "208" "(%%" "rbx" "), %%rsp \n"