2013-02-23 3 views
0

Добрый день. У меня возникла проблема, которую я не мог решить в течение нескольких дней. Ошибка возникает, когда я пытаюсь скомпилировать эту функцию на языке C.Встроенная сборка, попадание в прерывание

void GetInInterrupt(UChar Interrupt) 
{ 
    //asm volatile(".intel_syntax noprefix"); 
    asm volatile 
    (
     "movb %0, %%al\n" 
     "movb %%al, 1(point)\n" 
     "point:\n" 
     "int $0\n" 
     : /*output*/ : "r" (Interrupt) /*input*/ : /*clobbered*/ 
    ); 
    //asm volatile(".att_syntax noprefix"); 
} 

Сообщение Я получаю от газа следующее:

Error: junk '(point)' after expression 

Как я могу понять, указатель на второй линии неисправен, но, к сожалению, я не могу решить ее самостоятельно.


Благодарим за помощь.

+0

Что вы на самом деле пытаетесь сделать [и вы должны добавить '' al "' (или eax) в свой «сбитый список», иначе компилятор рано или поздно сделает что-то с помощью eax, который разрушит ваши планы здесь. Вы хотите вызвать деление на нулевую ошибку? –

+0

добавление «al» в список закладок - хорошая идея, спасибо. Я действительно хочу изменить $ 0 после команды «int» на значение, хранящееся в переменной «Прерывание» – hrust

+1

Вы не можете этого сделать - код доступен только для чтения. Вам нужно будет написать намного больше кода, включая добавление кода для 'mprotect' или' VirtualProtect', чтобы вы могли указывать код для чтения-записи, а не только для чтения. Почему вы не знаете, какое прерывание вы хотите назвать? –

ответ

2

Если вы можете использовать C++, то это одно:

template <int N> static inline void GetInInterrupt (void) 
{ 
    __asm__ ("int %0\n" : "N"(N)); 
} 

будет делать. Если я использую этот шаблон, как:

GetInInterrupt<123>(); 
GetInInterrupt<3>(); 
GetInInterrupt<23>(); 
GetInInterrupt<0>(); 

, который создает следующий код объекта:

0: cd 7b     int $0x7b 
    2: cc      int3 
    3: cd 17     int $0x17 
    5: cd 00     int $0x0 

, которая в значительной степени оптимальная (даже для int3 случае, что точка останова оп). Он также создаст предупреждение о компиляции, если операнд находится вне диапазона 0..255 из-за ограничения N, допускающего только это.

Edit: простые старые макросы C-стиль работы, а также, конечно:

#define GetInInterrupt(arg) __asm__("int %0\n" : : "N"((arg)) : "cc", "memory") 

создает тот же код, что и ++ шаблонных функций C. Из-за того, как ведет себя int, рекомендуется сказать компилятору (с помощью ограничений "cc", "memory") о семантике барьера, чтобы убедиться, что он не пытается переупорядочить инструкции при встраивании встроенной сборки.

Ограничение обоих - это, очевидно, тот факт, что номер прерывания должен быть константой времени компиляции. Если вы этого абсолютно не хотите, то создайте оператор switch(), созданный, например. с помощью BOOST_PP_REPEAT() охватывающей все 255 случаев является лучшим вариантом, чем самомодифицирующимся код, т.е. как:

#include <boost/preprocessor/repetition/repeat.html> 

#define GET_INTO_INT(a, INT, d) case INT: GetInInterrupt<INT>(); break; 

void GetInInterrupt(int interruptNumber) 
{ 
    switch(interruptNumber) { 
    BOOST_PP_REPEAT(256, GET_INTO_INT, 0) 
    default: 
     runtime_error("interrupt Number %d out of range", interruptNumber); 
    } 
} 

Это может быть сделана в простом C (если вы измените шаблонный вызов функции для простого __asm__ конечно) - потому что библиотека препроцессора boost делает не зависит от компилятора C++ ... и gcc 4.7.2 создает следующий код для этого:


GetInInterrupt: 
.LFB0: 
     cmpl $255, %edi 
     jbe  .L262 
     movl %edi, %esi 
     xorl %eax, %eax 
     movl $.LC0, %edi 
     jmp  runtime_error 
     .p2align 4,,10 
     .p2align 3 
.L262: 
     movl %edi, %edi 
     jmp  *.L259(,%rdi,8) 
     .section  .rodata 
     .align 8 
     .align 4 
.L259: 
     .quad .L3 
     .quad .L4 
[ ... ] 
     .quad .L258 
     .text 
.L257: 
#APP 
# 17 "tccc.c" 1 
     int $254 

# 0 "" 2 
#NO_APP 
     ret 
[ ... accordingly for the other vectors ... ] 

Берегись, хотя, если вы делаете выше ... компилятор (GCC вплоть до 4.8) не достаточно умна, чтобы оптимизировать switch() прочь, то есть даже если вы скажете static __inline__ ..., это создаст полную версию таблицы прыжков GetInInterrupt(3) вместо просто встроенного int3, а также более простые реализации.

+0

У вас недостает второй: в этом шаблоне. Я думаю, что это может быть: template static inline void raiseInterrupt (void) { asm volatile ("int% 0 \ n":: "N" (N)); } – JCx

2

Ниже показано, как вы можете записать местоположение в коде. Он предполагает, что код в первую очередь записывается, что обычно не относится к основным ОС - поскольку это скроет некоторые неприятные ошибки.

void GetInInterrupt(UChar Interrupt) 
{ 
    //asm volatile(".intel_syntax noprefix"); 
    asm volatile 
    (
     "movb %0, point+1\n" 
     "point:\n" 
     "int $0\n" 
     : /*output*/ : "r" (Interrupt) /*input*/ : /*clobbered */ 
    ); 
    //asm volatile(".att_syntax noprefix"); 
} 

Я также упростил код, чтобы избежать использования двух регистров, и вместо того, чтобы просто использовать регистр, который Interrupt уже есть. Если компилятор стонет об этом, вы можете обнаружить, что вместо того, чтобы "a" или "r" решает эту проблему.

+0

Этот код изменяет память команд, но не сбрасывает конвейер cpu. Таким образом, может быть вызвано неправильное прерывание. – random

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