2015-11-07 38 views
5

Napisałem niestandardowe wywołanie systemowe dla przypisania, które porównuje dwie liczby całkowite i zwraca największą wartość. Tu jest mój kodu po stronie jądra (max.c):Linux - Dlaczego niestandardowe wywołanie systemowe nie działa poprawnie z liczbami ujemnymi?

#include <linux/kernel.h> 
#include <linux/syscalls.h> 

asmlinkage long sys_max(int num1, int num2) 
{ 
    if (num1 > num2) 
    { 
    return num1; 
    } 

    else 
    { 
    return num2; 
    } 
} 

A oto mój kod przestrzeni użytkownika (max.h):

#include <unistd.h> 
#define SYS_MAX 323 

int max(int num1, int num2) 
{ 
    int maxnumber = syscall(SYS_MAX, num1, num2); 
    return maxnumber; 
} 

Używam ten mały program do testowania systemu zadzwoń:

#include <stdio.h> 
#include <max.h> 

int main() 
{ 
    int a, b; 
    scanf("%d", &a); 
    scanf("%d", &b); 
    printf("%d", max(a, b)); 
    return 0; 
} 

to działa świetnie dla liczb dodatnich, lub gdy jeden jest dodatni, a drugi ujemny, ale max zawsze zwraca -1 gdy mamy do czynienia z dwiema wartościami ujemnymi. Zastanawiałem się, czy to z powodu int-> długiej konwersji, ale nie mogę zrozumieć, co powoduje problem.

+0

'int max (int num1, int num2) {}' - to definicja funkcji, a nie deklaracja. Czy chodziło Ci o 'int max (int, int);'? – melpomene

+0

Czy coś się zmieni, jeśli zmienisz nazwę funkcji 'max' na' mymax'? – melpomene

+0

@melpomene Angielski nie jest moim ojczystym językiem, więc nie jestem pewien, jakie jest właściwe słowo. Ale chodzi o to, że funkcja max musi zwracać liczbę całkowitą i otrzymywać dwie liczby całkowite jako parametry. –

Odpowiedz

10

Jeśli wywołanie systemowe zwraca wartość ujemną, jest traktowane jako błąd, a specjalny kod obsługi błędów jest wywoływany w bibliotece libc. Mianowicie, zwracana wartość jest negowana i przenoszona do globalnej zmiennej errno, a zwracana wartość wywołania systemowego staje się -1.

Właściwie podczas czytania o tym odkryłem, że na Linuksie, only values from -4095 to -1 are treated as errors, ale to nie jest ani przenośne, ani pomocne, jeśli chcesz, aby twoja funkcja działała na jakichkolwiek możliwych wartościach.

Podsumowując, nie można bezpiecznie użyć zwracanej wartości syscall, aby zwrócić wartość, która może być ujemna. Zwykłą konwencją byłoby przekazanie wskaźnika do zmiennej docelowej w celu zatrzymania wyniku i zarezerwowanie kodu powrotu na sukces/niepowodzenie. Zauważ, że robiąc to przy pomocy syscall będziesz pracował ze wskaźnikiem przestrzeni użytkownika z jądra-przestrzeni, więc copy_to_user będzie konieczne, aby zapisać wynik.

+0

Wielkie dzięki za wysiłek i odpowiedź. Mam problemy z implementacją funkcji copy_to_user i copy_from_user. Wszelkie wskazówki, jak to zrobić? –

+0

@BernardoLopes to kolejne pytanie, na które nie umiem odpowiedzieć. Poszukaj odpowiedzi, a jeśli nie możesz tego rozgryźć, zadaj nowe pytanie na SO :) – hobbs

+0

Dzięki, spróbuję z nowym kodem. Powiadomię, kiedy zakończy się kompilacja. –