Поднятие БРК в сборке на i386 Linux

Я обнаружил и изучил ошибку сегментации доступа к памяти x86, и она не будет работать в моем коде. Разница, возможно, в том, что я не использую отдельные сегменты .text и .data, а сохраняю все в одном сегменте, создавая собственный заголовок ELF. Объясняет ли это, почему вызов SYS_BRK терпит неудачу?

Затем программа продолжает работу, заставляя страницы памяти читать/записывать/выполнять и т. д. Я попытался найти минимальный пример кода, иллюстрирующий проблему.

В kdbg образец работает, но не при запуске из командной строки, поэтому сообщение печатается.

            cpu   386
            bits  32

; System calls used
%assign     SYS_EXIT    1
%assign     SYS_WRITE   4
%assign     SYS_BRK     45
%assign     SYS_MPROTECT 125

; flags for SYS_MPROTECT
%assign     PROT_READ   1
%assign     PROT_WRITE  2
%assign     PROT_EXEC   4

%assign     STDOUT      1

memstart:   org         0x08048000

ehdr:                                           ; Elf32_Ehdr (see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
            db      0x7F, "ELF"                 ; e_ident[EI_MAG0..EI_MAG03]
            db      1                           ; e_ident[EI_CLASS]
            db      1                           ; e_ident[EI_DATA]
            db      1                           ; e_ident[EI_VERSION]
            db      0                           ; e_ident[EI_OSABI]
            db      0                           ; e_ident[EI_ABIVERSION]
  times 7   db      0                           ; e_ident[EI_PAD]
            dw      2                           ; e_type
            dw      3                           ; e_machine
            dd      1                           ; e_version
            dd      start                       ; e_entry
            dd      phdr - $$                   ; e_phoff
            dd      0                           ; e_shoff
            dd      0                           ; e_flags
            dw      ehdrsize                    ; e_ehsize
            dw      phdrsize                    ; e_phentsize
            dw      1                           ; e_phnum
            dw      0                           ; e_shentsize
            dw      0                           ; e_shnum
            dw      0                           ; e_shstrndx
ehdrsize    equ     $ - ehdr

phdr:                                           ; Elf32_Phdr
            dd      1                           ; p_type
            dd      0                           ; p_offset
            dd      $$                          ; p_vaddr
            dd      $$                          ; p_paddr
            dd      filesize                    ; p_filesz
            dd      filesize                    ; p_memsz
            dd      5                           ; p_flags
            dd      0x1000                      ; p_align
phdrsize    equ     $ - phdr

memsize:    dd      16*4096                     ; = 16 * 4K pages
memtop:     dd      0


start:      ;int     3
            xor     ebx, ebx                    ; find the amount of allocated memory
            mov     eax, SYS_BRK
            int     0x80                        ; eax contains current memtop

            sub     eax, memstart               ; got enough memory?
            test    eax, [memsize]
            ja      memgood

            mov     eax, memstart               ; raise memory limit to memstart + memsize
            add     eax, [memsize]
            mov     ebx, eax
            mov     ecx, eax                    ; save requested memory size in ecx
            mov     eax, SYS_BRK
            int     0x80
            cmp     eax, ecx
            jne     brk_error                   ; raising memory limit failed

memgood:    mov     edx, (PROT_READ | PROT_WRITE | PROT_EXEC)
            mov     ecx, [memsize]              ; make memory read/write/execute
            mov     ebx, memstart
            mov     eax, SYS_MPROTECT
            int     0x80
            test    eax, eax
            js      bailout

            jmp     launch                      ; lets start the party


brk_error:  mov     edx, brkelen
            mov     ecx, brke
            mov     ebx, STDOUT
            mov     eax, SYS_WRITE
            int     0x80
            jmp     bailout
brke:       db      'SYS_BRK failed, bye', 10
brkelen     equ     $ - brke

bailout:    mov     eax, SYS_EXIT
            xor     ebx, ebx
            int     0x80

launch:     mov     edx, succlen
            mov     ecx, succ
            mov     ebx, STDOUT
            mov     eax, SYS_WRITE
            int     0x80
            jmp     bailout
succ:       db      'Success with mem config, bye', 10
succlen     equ     $ - succ

filesize    equ $ - $$

person LNoor    schedule 03.04.2016    source источник
comment
Я видел ваш ответ и убедился, что он работает. Заголовок обычный, за исключением одного сегмента, поэтому нет разделения код/данные/bss. (ой, попадают вдруг посты). Я редактирую вопрос, чтобы показать полную инициализацию, но это не имеет значения, поэтому я пропустил эти части.   -  person LNoor    schedule 03.04.2016
comment
Извините, (первый пользователь). Проблема с моим кодом заключается во втором вызове BRK. Когда я помещаю int 3 перед int 128, я получаю ожидаемое сообщение о точке останова отладчика. Если я поставлю его после того, как программа никогда туда не попадет. При запуске из консоли программа просто зависает.   -  person LNoor    schedule 03.04.2016
comment
Я удалил все свои комментарии, потому что теперь вы предоставили фактический код, лол.   -  person Michael Petch    schedule 03.04.2016
comment
Я еще не закончил понимать ваш код, но смешивание кода и данных приводит к неэффективному использованию кеша L1. Процессоры Intel и AMD используют разделенные кэши L1I и L1D, поэтому, например, для загрузки строки brke потребуется, чтобы эта строка кэша находилась в кэше L1D, а окружающий код потребует, чтобы строка кэша находилась в кэше L1I. OTOH, это означает, что линия горячая в L2. Кроме того, вы делаете выборку кода менее эффективной, если вам приходится jmp перегружать данные. Обычно вы помещаете строки и другие данные только для чтения в .rodata, что группирует их вместе отдельно от кода, но все же в разделе .text.   -  person Peter Cordes    schedule 03.04.2016


Ответы (1)


Вы должны использовать здесь cmp вместо test:

    sub     eax, memstart               ; got enough memory?
    test    eax, [memsize]
    ja      memgood

Область памяти, описанная SYS_BRK, начинает со случайным смещением от 0 до 0x02000000 после исполняемого файла, если рандомизация макета адресного пространства не отключена, что, как я подозреваю, делает ваш отладчик. Вы можете использовать mmap для выделения памяти по указанному адресу (не устанавливайте MAP_FIXED, если вы не хотите перезаписывать существующие сопоставления).

Однако все это упражнение с brk и mprotect кажется довольно бессмысленным, поскольку помимо стека при запуске программы память выделяется точно так, как указано в заголовке ELF, вместо этого вы можете:

phdr:                                           ; Elf32_Phdr
            dd      1                           ; p_type
            dd      0                           ; p_offset
            dd      $$                          ; p_vaddr
            dd      $$                          ; p_paddr
            dd      filesize                    ; p_filesz
            dd      16*4096                     ; p_memsz
            dd      7                           ; p_flags
            dd      0x1000                      ; p_align
phdrsize    equ     $ - phdr
person Timothy Baldwin    schedule 03.04.2016
comment
Спасибо Тимоти. Это, вероятно, путь. Программа как бы перезаписывает и увеличивает себя, требуя для этого дополнительное место. Я не рассматривал рандомизацию расположения адресного пространства. Но изменение заголовка Elf и перезапуск должны помочь. - person LNoor; 04.04.2016
comment
Решением оказалось отключение рандомизации адресного пространства. Таким образом, программа запускается как setarch $(uname -m) -RL ./lf, что решило проблему. Спасибо @Тимоти. См. [stackoverflow.com/questions/5194666/ . - person LNoor; 05.04.2016