2015-03-03 3 views
0

Я стараюсь писать очень простые буквы, чтобы лучше понять основные принципы. И мне нужно реализовать malloc-пространство пользователя. Поэтому сначала я хочу реализовать и протестировать его на моей Linux-машине.Почему моя реализация системного вызова sbrk не работает?

Сначала я реализовал функцию sbrk() следующим образом

void* sbrk(int increment) { 
    return (void*)syscall(__NR_brk, increment); 
} 

Но этот код не работает. Вместо этого, когда я использую sbrk, данный os, это работает отлично.

я судимое использовать другую реализацию sbrk()

static void *sbrk(signed increment) 
{ 
    size_t newbrk; 
    static size_t oldbrk = 0; 
    static size_t curbrk = 0; 

    if (oldbrk == 0) 
     curbrk = oldbrk = brk(0); 

    if (increment == 0) 
     return (void *) curbrk; 

    newbrk = curbrk + increment; 

    if (brk(newbrk) == curbrk) 
     return (void *) -1; 

    oldbrk = curbrk; 
    curbrk = newbrk; 

    return (void *) oldbrk; 
} 

sbrk вызывается из этой функции

static Header *morecore(unsigned nu) 
{ 
    char *cp; 
    Header *up; 

    if (nu < NALLOC) 
     nu = NALLOC; 

    cp = sbrk(nu * sizeof(Header)); 
    if (cp == (char *) -1) 
     return NULL; 

    up = (Header *) cp; 
    up->s.size = nu; // ***Segmentation fault 
    free((void *)(up + 1)); 

    return freep; 
} 

Этот код также не работает, на линии (***) Я получаю ошибку сегментации. Где проблема?

Спасибо всем. Я решил проблему, используя новую реализацию sbrk. Данный код работает отлично.

void* __sbrk__(intptr_t increment) 
{ 
    void *new, *old = (void *)syscall(__NR_brk, 0); 

    new = (void *)syscall(__NR_brk, ((uintptr_t)old) + increment); 

    return (((uintptr_t)new) == (((uintptr_t)old) + increment)) ? old : 
     (void *)-1; 
} 
+1

Интересный вопрос, но вы, вероятно, должны расшириться на «не работает». – Tyler

+0

Я упомянул причину проблемы.См. Выше. –

+0

Почему вы пытаетесь «эмулировать» системный стол, например 'sbrk'? Вы должны изменить свой вопрос, чтобы мотивировать это. –

ответ

2

Первый sbrk, вероятно, следует иметь long increment. И вы забыли обработать ошибки (и установить errno)

Вторая функция sbrk не меняет address space (как sbrk). Вы можете использовать mmap, чтобы изменить его (но с помощью mmap вместо sbrk не будет обновлять представление ядра на конце сегмента данных, как sbrk). Вы можете использовать cat /proc/1234/maps для запроса адресного пространства процесса pid 1234). или даже читать (например, с fopen & fgets) /proc/self/maps из вашей программы.

КСТАТИ sbrk является устаревшим (большинство реализаций таНоса использовать mmap), и по определению каждый system call (перечислено в syscalls(2)) выполняются ядром (для sbrkядра поддерживает «сегмент данных» предел!). Поэтому вы не можете избежать ядра, и я даже не понимаю, почему вы хотите эмулировать любой системный вызов. Почти по определению вы не можете эмулировать системные вызовы, поскольку они являются единственным способом взаимодействия с ядром из пользовательского приложения. Из пользовательского приложения каждый системный столбец представляет собой атомную элементарную операцию (выполняемую одной машинной машиной SYSENTER с соответствующим содержимым в машинных регистрах).

Вы можете использовать strace(1), чтобы понять фактические системные вызовы, выполняемые вашей программой.

BTW, GNU libc является free software. Вы можете изучить его исходный код. musl-libc является более простым libc, и его код является более читаемым.

Наконец-то скомпилируйте с помощью gcc -Wall -Wextra -g и используйте отладчик gdb (вы даже можете запросить регистры, если хотите). Возможно, прочитайте x86/64-ABI specification и Linux Assembly HowTo.