错误:无法插入模块。模块中的未知符号

时间:2012-10-06 21:55:03

标签: c gcc linux-kernel x86-64 inline-assembly

我正在尝试将RR0D Rasta Ring0 Debugger从32位Linux移植到64位Linux。我已经使用vim正则表达式将32位gcc内联汇编转换为64位,如我的问题所述:How to convert Linux 32-bit gcc inline assembly to 64-bit code?

我正在使用带有-m64标志的gcc。目标环境是Linux x86-64,自定义内核版本3.5.5。

Makefile如下:

EXTRA_CFLAGS +=  -O2 -Wall -DLINUX_26 -m64

OBJ          := module_nux.o breakpoint.o buffering.o command.o disasmbak.o idt.o 
OBJ          += keyboard.o page.o video.o utils.o import_symb.o core_rr0d.o pci.o
MODULE       := rr0d.o 

obj-m        := $(MODULE)
rr0d-objs    := $(OBJ)

default:
    make -C /lib/modules/`uname -r`/build/ SUBDIRS=`pwd` modules

clean:
    rm -f  *.o .*.o.cmd .*.ko.cmd *.mod.c  *~ 
    rm -rf .tmp_versions

mrproper:
    make clean
    rm -f *.ko

make提供了许多警告,例如warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]warning: cast from pointer to integer of different size [-Wpointer-to-int-cast],但这些警告可能与该主题无关。

make输出的最后几行可能是重要的:

/home/user/code/rr0d/0.3/core_rr0d.c: In function ‘cleanup_rr0d’:
/home/user/code/rr0d/0.3/core_rr0d.c:1938:36: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
  CC [M]  /home/user/code/rr0d/0.3/pci.o
  LD [M]  /home/user/code/rr0d/0.3/rr0d.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "RING_HOOO_SEGMENT" [/home/user/code/rr0d/0.3/rr0d.ko] undefined!
  CC      /home/user/code/rr0d/0.3/rr0d.mod.o
  LD [M]  /home/user/code/rr0d/0.3/rr0d.ko
make[1]: Leaving directory `/home/user/code/kernel/linux-3.5.5'

因此,RING_HOOO_SEGMENT未定义。

当我尝试insmodinsmod ./rr0d.ko为根的模块时,我得到:

Error: could not insert module ./rr0d.ko: Unknown symbol in module

使用dmesg | tail -n 1进行检查会得到以下输出:

[15975.412346] rr0d: Unknown symbol RING_HOOO_SEGMENT (err 0)

因此,未知符号最终为RING_HOOO_SEGMENT

RING_HOOO_SEGMENT#define中使用vars.h创建的常量,包含在.c#include "vars.h"个文件中。

#ifdefvars.h的基本#define RING_HOOO_SEGMENT块是这一块:

#ifdef LINUX_26

#define fake_naked

#if defined(__GNUC__)
// the line below is the important one.
#define RING_HOOO_SEGMENT "$0x7b"
//#define       RING_HOOO_SEGMENT "$0x60"
#elif defined(_MSC_VER)
#define RING_HOOO_SEGMENT 0x7b
#endif

#else /* LINUX_24 */

#define fake_naked _asm_("\t" \
                     "add $0x08, %esp\n\t" \
                     "popl %ebp\n" \
);

#if defined(__GNUC__)
#define RING_HOOO_SEGMENT "$0x18"
#elif defined(_MSC_VER)
#define RING_HOOO_SEGMENT 0x18
#endif

#define RING_HOOO_SEGMENT_VALUE 0x18

#endif /* LINUX_26 */

显然,如果#define RING_HOOO_SEGMENT "$0x7b"(在#if defined(__GNUC__)#ifdef LINUX_26)被注释掉,代码将无法编译,因此很明显RING_HOOO_SEGMENT已被定义。

RING_HOOO_SEGMENT加注以下匹配项:

$ grep 'RING_HOOO_SEGMENT' *.c *.o *.ko

core_rr0d.c:    "movq RING_HOOO_SEGMENT, %rax\n\t"\
core_rr0d.c:  __asm{    movq RING_HOOO_SEGMENT, %rax}\
Binary file rr0d.ko matches

两个core_rr0d.c行都是内联汇编。 core_rr0d.c包含#include "vars.h",因此应该没问题。

二进制模块rr0d.ko也匹配,因此它包含字符串RING_HOOO_SEGMENT(以某种形式),即使insmod ./rr0d.koError: could not insert module ./rr0d.ko: Unknown symbol in module而失败。

任何想法可能导致此问题的原因以及如何继续insmod模块?

1 个答案:

答案 0 :(得分:2)

core_rr0d.c:    "movq RING_HOOO_SEGMENT, %rax\n\t"\

这里RING_HOOO_SEGMENT是一个字符串(可能是内联汇编程序块的一部分)。因此,预处理器不会替换RING_HOOO_SEGMENT,它会按原样传递给汇编程序,而RING_HOOO_SEGMENT的定义不可用。

幸运的是,RING_HOOO_SEGMENT本身被定义为字符串"$0x7b",因此我们可以使用编译时字符串连接:

"movq " RING_HOOO_SEGMENT ", %rax\n\t"\

预处理器将RING_HOOO_SEGMENT替换为"$0x7b",然后GCC会在将这些字符串传递给汇编程序之前将它们连接起来。