2013-02-23 2 views
0

안녕하십니까. 며칠 동안 해결할 수없는 문제에 직면했습니다. C 언어로이 함수를 컴파일하려고하면 오류가 나타납니다. 내가 두 번째 줄에있는 포인터를 이해할 수 있듯이인라인 어셈블리, 인터럽트 들어가기

Error: junk '(point)' after expression 

에 결함이 있지만, 불행히도 나는 내 자신에 의해 그것을 해결할 수 : 나는 가스로부터 얻을

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"); 
} 

메시지는 다음입니다.


감사합니다.

+0

실제로 무엇을하려고합니까? 그리고 "clobbered list"에''al "'(또는 eax)를 추가해야합니다. 아니면 컴파일러가 여러분의 계획을 망칠 eax로 조만간 뭔가를 할 것입니다. 0으로 나누기 오류를 호출 하시겠습니까? –

+0

"al"을 clobbered 목록에 추가하는 것이 좋습니다. 감사합니다. "int"명령 다음에 "인터럽트"변수에 저장된 값으로 $ 0을 변경하려고합니다. – hrust

+1

당신은 할 수 없습니다 - 코드는 읽기 전용입니다. 'mprotect' 또는'VirtualProtect'에 코드를 추가하는 것을 포함하여 훨씬 더 많은 코드를 작성해야합니다. 그러면 코드를 읽기 전용 대신 읽기 - 쓰기로 설정할 수 있습니다. 어떤 인터럽트를 호출할지 알지 못하는 이유는 무엇입니까? –

답변

2

:

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

할 것입니다. 내가 사용하는 경우 해당 템플릿과 같은 :

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

(심지어는 중단 영업 이익 인 int3 경우, 위해) 거의 최적 다음 오브젝트 코드를 생성

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

. 피연산자가 0..255 범위를 벗어나면 N 제약 조건 만 허용되므로 컴파일 타임 경고가 생성됩니다.

편집 : 보통 오래된 C 스타일 매크로는 물론, 잘 작동 :

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

는 C++ 템플릿 함수와 같은 코드를 작성합니다. int의 작동 방법으로 인해 컴파일러에게 ("cc", "memory" 제약 조건을 통해) 장벽 의미에 대해 알리고 인라인 어셈블리를 포함 할 때 지침을 다시 주문하지 않도록하십시오.

두 가지 제한은 분명히 인터럽트 번호가 컴파일 타임 상수 여야한다는 사실입니다. 당신이 그것을 원하지 않는다면, 예를 들어 switch() 문을 생성하십시오. 모든 2백55가지 경우를 포함하는 BOOST_PP_REPEAT()의 도움으로 자기 수정 코드보다 더 나은 옵션입니다으로, 즉 같은 :

#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); 
    } 
} 

당신이 __asm__ 일반의 템플릿 함수 호출을 변경하면이 (일반 C에서 할 수 있습니다 물론) - 부스트 전처리 기 라이브러리가 이 아니기 때문에은 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 ... ] 

그래도 조심 위 ... 컴파일러를 할 경우 (그리고 4.8를 포함하여 최대 GCC)입니다 하지 즉 경우에도, 멀리 switch()을 최적화 할만큼 지능static __inline__ ...라고 말하면 더 간단한 구현처럼 인라인 대신 GetInInterrupt(3)의 전체 점프 테이블 버전을 생성합니다.

+0

그 템플릿에 잠깐 빠져 있습니까? 나는 그것이 필요할 수도 있다고 생각한다 : 템플릿 정적 인라인 void raiseInterrupt (void) { asm volatile ("int % 0 \ n": "N"(N)); } – JCx

2

다음은 코드에서 위치를 작성하는 방법을 보여줍니다. 코드가 처음부터 쓰기 가능하다고 가정합니다.이 코드는 일반적으로 주류 OS에서는 그렇지 않습니다. 그 때문에 일부 불쾌한 버그가 숨겨지기 때문입니다.

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" 문제를 해결 찾을 수 있습니다. 당신이 다음이 하나의 C++를 사용할 수있는 경우

+0

이 코드는 명령 메모리를 수정하지만 cpu 파이프 라인을 비우지 않습니다. 따라서 잘못된 인터럽트가 호출 될 수 있습니다. – random