Неопределенная ссылка на C Macro, но при переопределении я получаю переопределенную ошибку - PullRequest
2 голосов
/ 23 февраля 2020

У меня есть макрос, определенный в 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
      | 

Итак, компилятор знает о KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET в системном вызове. cc. Тогда почему компоновщик не может видеть определение ??

1 Ответ

2 голосов
/ 23 февраля 2020

Компоновщик не занимается поиском макросов. Макросы обрабатываются препроцессором, который запускается задолго до компоновщика. Если компоновщик жалуется на неопределенную ссылку, это означает, что расширение макроса пошло не так. Он излучает 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"

, тогда как вы хотите, чтобы она расширялась into (используя значение в kthread.h)

"movq " "208" "(%%" "rbx" "), %%rsp \n"

Причина, по которой это происходит, заключается в том, как обрабатываются аргументы для работы подобно макросам. Они не имеют промежуточного раскрытия go при использовании в операторе строкового кодирования #.

Вы можете обойти это, введя слой косвенности.

#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"
...