2016-02-12 2 views
3

Я реализую функцию MMAP с помощью системного вызова (я реализую ММАП вручную из-за рядом причин.)ММАПА возвращение -14 (-EFAULT ??)

Но я получаю возвращаемое значение -14 (. - EFAULT, я проверил с GDB) ти это сообщение:

WARN Nar::Mmap: Memory allocation failed. 

Вот функция:

void *Mmap(void *Address, size_t Length, int Prot, int Flags, int Fd, off_t Offset) { 
    MmapArgument ma; 
    ma.Address = (unsigned long)Address; 
    ma.Length = (unsigned long)Length; 
    ma.Prot = (unsigned long)Prot; 
    ma.Flags = (unsigned long)Flags; 
    ma.Fd = (unsigned long)Fd; 
    ma.Offset = (unsigned long)Offset; 
    void *ptr = (void *)CallSystem(SysMmap, (uint64_t)&ma, Unused, Unused, Unused, Unused); 
    int errCode = (int)ptr; 
    if(errCode < 0) { 
     Print("WARN Nar::Mmap: Memory allocation failed.\n"); 
     return NULL; 
    } 
    return ptr; 
} 

Я написал макрос (Для того, чтобы использовать как таНос() функции):

#define Malloc(x) Mmap(0, x, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) 

и я так:

Malloc(45); 

Я посмотрел на человека странице. Я не мог найти информацию о EFAULT на странице mmap man, но я нашел что-то о EFAULT на странице manap2 man.

EFAULT Проблема с получением данных из пользовательского пространства.

Я думаю, что это означает, что что-то не так с передачей struct в системный вызов. Но я считаю, нет ничего плохого в моих структурах:

struct MmapArgument { 
    unsigned long Address; 
    unsigned long Length; 
    unsigned long Prot; 
    unsigned long Flags; 
    unsigned long Fd; 
    unsigned long Offset; 
}; 

Может что-то не так со значением результата вручая? Открыв файл (который не существует) с CallSystem дал мне -2 (-ENOENT), что верно.

EDIT: Полный источник CallSystem. открывать, писать, закрывать работы, но mmap (или old_mmap) не работает. Все аргументы были приняты хорошо.

section  .text 

global CallSystem 
CallSystem: 
    mov rax, rdi  ;RAX 
    mov rbx, rsi  ;RBX 

    mov r10, rdx 
    mov r11, rcx 
    mov rcx, r10  ;RCX 
    mov rdx, r11  ;RDX 

    mov rsi, r8  ;RSI 
    mov rdi, r9  ;RDI 

    int 0x80 
    mov rdx, 0 ;Upper 64bit 
    ret     ;Return 
+0

Исходный код для 'CallSystem'. – gudok

+2

Просьба предоставить минимальный, но полный примерный код. Кроме того, удалите все макросы (они злы, рассмотрите встроенные функции или константы) и все ненужные роли. Затем, что произойдет, если вы запустите минимальный пример и эквивалент, используя команду 'mmap()', используя 'strace'? О, и, пожалуйста, решите для одного из C и C++. –

+0

Нет кода для преобразования формата 'MmapArgument' в формат, который ожидает системный вызов. Этот код может работать только по волшебству. –

ответ

2

Неясно, почему вы звоните mmap через ваш CallSystem функции, я буду считать, что это требование вашего задания.

Основная проблема с вашим кодом в том, что вы используете int 0x80. Это будет работать, только если все адреса, переданные в int 0x80, могут быть выражены в 32-битовом целое. Это не так в вашем коде. Эта строка:

MmapArgument ma; 

размещает вашу структуру в стеке. В 64-битном коде стек находится в верхнем конце адресного адресного пространства, намного превышающем то, что может быть представлено в 32-разрядном адресе. Обычно нижняя часть стека находится где-то в области 0x00007FFFFFFFFFFF. int 0x80 работает только в нижней половине 64-разрядных регистров, поэтому эффективные адреса на основе стека усекаются, что приводит к неправильному адресу. Для того, чтобы обеспечить надлежащее 64-разрядную систему вызовов предпочтительно, чтобы использовать syscall ИНСТРУКЦИЯ

64-bit System V ABI имеет раздел общего механизма для интерфейса syscall в разделе A.2.1 AMD64 Linux Kernel конвенций. Он говорит:

  1. приложений на уровне пользователя использовать как целочисленные регистры для прохождения последовательности% RDI,% риши,% гексогена,% RCX,% r8 и% R9.Интерфейс ядра использует% rdi, % rsi,% rdx,% r10,% r8 и% r9.
  2. Системный вызов выполняется с помощью команды syscall. Ядро уничтожает регистров% rcx и% r11.

Мы можем создать упрощенную версию SystemCall кода путем размещения systemcallnum в качестве последнего параметра. В качестве 7-го параметра это будет первое и единственное значение, переданное в стек. Мы можем перенести это значение из стека в RAX, который будет использоваться в качестве номера системного вызова. Первые 6 значений передаются в регистрах, и за исключением RCX мы можем просто сохранить все регистры как есть. RCX необходимо переместить в R10, поскольку 4-й параметр отличается от обычного вызова функции и ядра Linux. SYSCALL соглашение.

Некоторые упрощенный код для демонстрационных целей может выглядеть следующим образом:

global CallSystem 

section .text 
CallSystem: 

    mov rax, [rsp+8] ; CallSystem 7th arg is 1st val passed on stack 
    mov r10, rcx  ; 4th argument passed to syscall in r10 
         ; RDI, RSI, RDX, R8, R9 are passed straight through 
         ; to the sycall because they match the inputs to CallSystem 
    syscall 
    ret 

C++ может выглядеть следующим образом:

#include <stdlib.h> 
#include <sys/mman.h> 
#include <stdint.h> 
#include <iostream> 

using namespace std; 

extern "C" uint64_t CallSystem (uint64_t arg1, uint64_t arg2, 
           uint64_t arg3, uint64_t arg4, 
           uint64_t arg5, uint64_t arg6, 
           uint64_t syscallnum); 

int main() 
{ 
     uint64_t addr; 
     addr = CallSystem(static_cast<uint64_t>(NULL), 45, 
         PROT_READ | PROT_WRITE, 
         MAP_PRIVATE | MAP_ANONYMOUS, 
         -1, 0, 0x9); 
     cout << reinterpret_cast<void *>(addr) << endl; 
} 

В случае mmap системный вызов является 0x09. Это можно найти в файле asm/unistd_64.h:

#define __NR_mmap 9 

Остальные аргументы типичны для новой формы mmap. Из справочной системы:

void * mmap (void * addr, size_t length, int prot, int flags, int fd, off_t offset);

Если запустить strace на свой исполняемый файл (т.е. strace ./a.out), вы должны найти строку, которая выглядит следующим образом, если он работает:

mmap(NULL, 45, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fed8e7cc000 

Возвращаемое значение будет отличаться, но оно должно соответствовать тому, что демонстрация программных дисплеев.

У вас должен быть возможность адаптировать этот код к тому, что вы делаете. Это должно быть, по крайней мере, разумной отправной точкой.


Если вы хотите передать syscallnum в качестве первого параметра CallSystem вам придется изменить код сборки, чтобы переместить все регистры так, что они присоединяются должным образом между конвенцией вызова функции и syscall конвенциями. Я оставляю это как простое упражнение для читателя. Это даст намного менее эффективный код.

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