2012-03-18 2 views
3

Я пытаюсь вызвать системный вызов из модуля ядра, у меня есть этот код:системный вызов Linux из ядра сбою (странно офсет)

set_fs(get_ds()); // lets our module do the system-calls 


    // Save everything before systemcalling 

    asm ("  push %rax  "); 
    asm ("  push %rdi  "); 
    asm ("  push %rcx  "); 
    asm ("  push %rsi  "); 
    asm ("  push %rdx  "); 
    asm ("  push %r10  "); 
    asm ("  push %r8  "); 
    asm ("  push %r9  "); 
    asm ("  push %r11  "); 
    asm ("  push %r12  "); 
    asm ("  push %r15  "); 
    asm ("  push %rbp  "); 
    asm ("  push %rbx  "); 


    // Invoke the long sys_mknod(const char __user *filename, int mode, unsigned dev); 

    asm volatile ("  movq $133, %rax  "); // system call number 

    asm volatile (" lea path(%rip), %rdi  "); // path is char path[] = ".." 

    asm volatile ("  movq mode, %rsi  "); // mode is S_IFCHR | ... 

    asm volatile ("  movq dev, %rdx  "); // dev is 70 >> 8 

    asm volatile ("  syscall  "); 


     // POP EVERYTHING 

    asm ("  pop  %rbx  "); 
    asm ("  pop  %rbp  "); 
    asm ("  pop  %r15  "); 
    asm ("  pop  %r12  "); 
    asm ("  pop  %r11  "); 
    asm ("  pop  %r9  "); 
    asm ("  pop  %r8  "); 
    asm ("  pop  %r10  "); 
    asm ("  pop  %rdx  "); 
    asm ("  pop  %rsi  "); 
    asm ("  pop  %rcx  "); 
    asm ("  pop  %rdi  "); 
    asm ("  pop  %rax  "); 



    set_fs(savedFS); // restore the former address-limit value 

Этот код не работает, и сбой системы вниз (это модуль ядра).

Свалка этого куска кода с переездом Infos является:

2c: 50      push %rax 
    2d: 57      push %rdi 
    2e: 51      push %rcx 
    2f: 56      push %rsi 
    30: 52      push %rdx 
    31: 41 52     push %r10 
    33: 41 50     push %r8 
    35: 41 51     push %r9 
    37: 41 53     push %r11 
    39: 41 54     push %r12 
    3b: 41 57     push %r15 
    3d: 55      push %rbp 
    3e: 53      push %rbx 
    3f: 48 c7 c0 85 00 00 00  mov $0x85,%rax 
    46: 48 8d 3d 00 00 00 00  lea 0x0(%rip),%rdi  # 4d <init_module+0x4d> 
      49: R_X86_64_PC32 path-0x4 
    4d: 48 83 c7 04    add $0x4,%rdi 
    51: 48 8b 34 25 00 00 00  mov 0x0,%rsi 
    58: 00 
      55: R_X86_64_32S mode 
    59: 48 8b 14 25 00 00 00  mov 0x0,%rdx 
    60: 00 
      5d: R_X86_64_32S dev 
    61: 0f 05     syscall 
    63: 5b      pop %rbx 
    64: 5d      pop %rbp 
    65: 41 5f     pop %r15 
    67: 41 5c     pop %r12 
    69: 41 5b     pop %r11 
    6b: 41 59     pop %r9 
    6d: 41 58     pop %r8 
    6f: 41 5a     pop %r10 
    71: 5a      pop %rdx 
    72: 5e      pop %rsi 
    73: 59      pop %rcx 
    74: 5f      pop %rdi 
    75: 58      pop %rax 

Я интересно .. почему есть -0x4 смещение в 49: R_X86_64_PC32 путь-0x4?

Я имею в виду: режим и dev должны быть решены автоматически без проблем, но как насчет пути? Почему -0x4 смещение?

Я пытался "компенсировать это" с

LEA 0x0 (% плагиат),% RDI // это как-то добавляет -0x4 смещение добавить $ 0x4,% RDI ....

но код все еще разбился.

Где я ошибаюсь?

+4

Вы не можете вызвать системный вызов изнутри ядра. Ядро предоставляет системные вызовы приложениям. Что вы действительно хотите сделать? Не можете ли вы избежать работы на земле ядра? –

+0

Вот почему я положил set_fs (get_ds()); что должно увеличить предел сегмента, который может вызывать системные вызовы. Это упражнение для экзамена (http://cs.usfca.edu/~cruse/cs635/), поэтому мне нужно выяснить, как это сделать с помощью amd64 – paulAl

+0

Из комментария вызова вызова 'syscall':' rcx return address for syscall/sysret, C arg3'. –

ответ

0

Мое предположение о том, что происходит здесь, является проблемой стека. В отличие от int $0x80 инструкция syscall не будет устанавливать стек для ядра. Если вы посмотрите на фактический код от system_call:, вы увидите что-то вроде SWAPGS_UNSAFE_STACK. Мясо этого макроса - инструкция SwapGS - см. Стр. 152 here. Когда вводится режим ядра, ядро ​​требуется способ вывести указатель на свои структуры данных, и эта инструкция позволяет это сделать именно это. Он делает это путем замены пользователя %gs регистра со значением, сохраненным в регистре, зависящем от модели, из которого он может вытащить стек режима ядра.

Вы можете себе представить, что после того, как вызывается точка входа syscall, этот обмен производит неправильное значение, так как вы уже были в режиме ядра, а ядро ​​начинает пытаться использовать фиктивный стек. Вы можете попытаться вызвать SwapGS вручную, сделав результат SwapGS ядра ожидаемым и посмотрим, работает ли это.

+0

segmentation fault, dammit. Во всяком случае, я думаю, что вы правы, многое происходит, и я должен прочитать всю рутину syscall, чтобы выяснить, что случилось. Много времени. – paulAl

+0

извините, я дал вам неправильную ссылку выше. должны быть исправлены. Я также посмотрел бы псевдокод в спецификации AMD для инструкции syscall [здесь] (http://lars.nocrew.org/computers/processors/x86-64/24594.pdf) на стр. 345. По крайней мере, это поможет вам понять, что делает linux в процедуре system_call. Кстати, что именно происходило, когда вы сказали, что он рушится? Это заставило машину повесить трубку? напечатал ядро ​​oops? и т. д. Если это не висит на машине, вы можете попробовать запустить dmesg и искать что-то нечетное – kch

+0

нет, просто повесили – paulAl

0

Кажется, что вы не можете сделать это таким образом. Смотрите comment до того system_call:

/* 
    * Register setup: 
    * rax system call number 
    * rdi arg0 
    * rcx return address for syscall/sysret, C arg3 
    * rsi arg1 
    * rdx arg2 
    * r10 arg3 (--> moved to rcx for C) 
    * r8 arg4 
    * r9 arg5 
    * r11 eflags for syscall/sysret, temporary for C 
    * r12-r15,rbp,rbx saved by C code, not touched. 
    * 
    * Interrupts are off on entry. 
    * Only called from user space. 
    * 
    * XXX if we had a free scratch register we could save the RSP into the stack frame 
    *  and report it properly in ps. Unfortunately we haven't. 
    * 
    * When user can change the frames always force IRET. That is because 
    * it deals with uncanonical addresses better. SYSRET has trouble 
    * with them due to bugs in both AMD and Intel CPUs. 
    */ 

Итак, вы не можете назвать syscall из ядра. Но вы можете попробовать использовать int $0x80 для этих целей. Как я вижу, kernel_execve stub использует это trick

+0

Можно ли вызвать int 0x80 из 64-битной программы? Будет ли это работать? И мне нужно указать индекс 32-битных системных вызовов в rax, не так ли? – paulAl

+0

Оказывается, я НЕ МОЖЕТ использовать int 0x80 в 64-битном модуле ядра. Мне интересно, существует ли какой-либо механизм VA-whence-protection. – paulAl

+0

Зачем вам нужно «syscall»?Можете ли вы попытаться вызвать 'sys_mknod' напрямую? .. –

Смежные вопросы