Board.KolibriOS.org

Официальный форум KolibriOS
Текущее время: Пт авг 17, 2018 10:56 am

Часовой пояс: UTC+03:00




Начать новую тему  Ответить на тему  [ 7 сообщений ] 
Автор Сообщение
СообщениеДобавлено: Ср июн 06, 2018 12:50 pm 
Не в сети

Зарегистрирован: Пн дек 05, 2016 11:04 am
Сообщения: 113
в IRC-клиенте есть 2048-байтовый массив для хранения команд юзера:
Код:
MAX_COMMAND_LEN = 512
user_command rb MAX_COMMAND_LEN*4
в дальнейшем я пытаюсь очистить хотя бы первые 255 байт для начала, при помощи новой функции:
(в главном файле объявлен счётчик цикла "counter db 0")
Код:
clear_user_command:

    mov al, 0

    .cycle_clear:

    mov byte[counter], al
    mov byte[user_command + counter], 0 ; очищение байта в user_command
    add al, 1
    cmp al, 255
    jne .cycle_clear

    ; печать получившейся строки
    mov esi, user_command
    call print_asciiz

    ret
Казалось бы, этот простой и понятный цикл действительно должен заменить первые 255 байт у user_command нулями,
но после вызова этой функции ( call clear_user_command ) при выводе на печать я по-прежнему вижу неочищенное начало старой команды юзера.
Что я делаю не так?


Вернуться к началу
СообщениеДобавлено: Ср июн 06, 2018 2:03 pm 
Не в сети

Зарегистрирован: Ср мар 26, 2008 12:44 pm
Сообщения: 168
floppy121 писал(а):
Что я делаю не так?

Всё не так :)
Если вопрос - почему не работает, то причина в команде
Код:
    mov byte[user_command + counter], 0 ; очищение байта в user_command

Здесь user_command и counter это адреса переменных. Ты их складываешь (это делается на этапе ассемблирования), получая некий адрес, и записываешь туда байт 00. Всегда. По одному и тому-же адресу.

Что нужно сделать, чтобы заработал конкретно этот код. Ну, во-первых нужно использовать регистр eax, т.к. к адресу нужно прибавлять 32-битное значение. А во-вторых, вышеупомянутую команду нужно записать немного иначе. К тому-же никакой переменной counter не нужно, её роль будет играть регистр eax.

Код:
clear_user_command:

    mov eax, 0

    .cycle_clear:

    mov byte[user_command][eax], 0 ; очищение байта в user_command
    add eax, 1
    cmp eax, 255
    jne .cycle_clear

    ; печать получившейся строки
    mov esi, user_command
    call print_asciiz

    ret


Запись в память можно делать:
- по фиксированному адресу mov byte[user_command], 0
- по адресу в регистре mov byte[eax], 0
- или по сумме фиксированного значения и регистра mov byte[user_command][eax], 0

Команду mov eax, 0 обычно заменяют на более короткую (в коде) xor eax,eax
Команду add eax, 1 лучше заменить на более короткую inc eax

Но вообще, для заполнения области памяти имеется команда rep stosb (или rep stosd, которая быстрее, и записывает по 4 байта за цикл).


Вернуться к началу
СообщениеДобавлено: Ср июн 06, 2018 2:42 pm 
Не в сети

Зарегистрирован: Пн дек 05, 2016 11:04 am
Сообщения: 113
tsdima писал(а):
- или по сумме фиксированного значения и регистра mov byte[user_command][eax], 0

К сожалению именно этот, самый нужный пример, не собирается:
Код:
flat assembler  version 1.71.54
userparser.inc [501]:
    mov byte[user_command][eax], 0
error: invalid operand

При этом остальные два примера собираются нормально. Не могу понять в чём дело...


Вернуться к началу
СообщениеДобавлено: Ср июн 06, 2018 3:25 pm 
Не в сети

Зарегистрирован: Ср мар 26, 2008 12:44 pm
Сообщения: 168
floppy121 писал(а):
К сожалению именно этот, самый нужный пример, не собирается

Забыл, что fasm не любит такую запись. Попробуй mov byte[user_command+eax], 0


Вернуться к началу
СообщениеДобавлено: Ср июн 06, 2018 4:06 pm 
Не в сети

Зарегистрирован: Пн дек 05, 2016 11:04 am
Сообщения: 113
tsdima писал(а):
floppy121 писал(а):
К сожалению именно этот, самый нужный пример, не собирается

Забыл, что fasm не любит такую запись. Попробуй mov byte[user_command+eax], 0

Благодарю, сработало! :P вот что в итоге получилось:
ircc.asm
Код:
MAX_COMMAND_LEN         = 512
MAX_COMMAND_LEN_BYTES   = MAX_COMMAND_LEN*4
userparser.inc
Код:
clear_user_command:

    xor eax, eax

  .cycle_clear:

    mov byte[user_command + eax], 0
    inc eax
    cmp eax, MAX_COMMAND_LEN_BYTES
    jne .cycle_clear

    ret


Последний раз редактировалось floppy121 Чт июн 07, 2018 7:14 pm, всего редактировалось 1 раз.

Вернуться к началу
СообщениеДобавлено: Ср июн 06, 2018 6:44 pm 
Не в сети

Зарегистрирован: Вс окт 30, 2011 6:43 pm
Сообщения: 1300
Можно ещё добавить варианты, используемые в других программах.

Для заполнения области памяти байтами с определённым значением(в том числе нулевым) обычно используется memset.
Вот эта функция в Tiny C Compiler http://websvn.kolibrios.org/filedetails ... memset.asm
Код:
format ELF
section '.text' executable
public memset
memset:
  push  edi
  mov   edi,[esp+8]
  mov   eax,[esp+12]
  mov   ecx,[esp+16]
  jecxz  .no_set
  cld
  rep   stosb
.no_set:
  mov eax, [esp+8]
  pop   edi
  ret
А вот она же в программе graph http://websvn.kolibrios.org/filedetails ... memset.asm
Код:
format MS COFF
section '.text' code readable executable
public _memset
_memset:
        push    edi
        mov     edi, [esp+8]
        mov     al, [esp+12]
        mov     ecx, [esp+16]
        rep     stosb
        pop     edi
        ret
Я же в своей libc использую такой вариант
Код:
GLOBAL _memset

SECTION .text

;**********************************************************************************
_memset: ;//////////////////////////////////////////////////////////////////////////
;**********************************************************************************
%define ptr    [esp +  4 +1*4] ; Pointer to block of memory to fill
%define value  [esp +  8 +1*4] ; Value to be set
%define num    [esp + 12 +1*4] ; Number of bytes to set to value
DEBUG.PRINT.LINE "memset start"
        push   edi
        mov    eax, value
        mov    edx, num   
        mov    edi, ptr   
        mov    ecx, eax
        mov    ah, al
        mov    ch, cl
        shl    ecx, 16
        or     eax, ecx
        mov    ecx, edx
        shr    ecx, 2
        and    edx, 3
        rep stosd
        mov    ecx, edx
        rep stosb       
        mov    eax, ptr       
        pop    edi
DEBUG.PRINT.LINE "memset finish"
        ret
%undef ptr
%undef value
%undef num
       
Вот функция FillChar из RTL Delphi7
Код:
{     ->EAX     Pointer to destination  }
{       EDX     count   }
{       CL      value   }
        PUSH    EDI
        MOV     EDI,EAX { Point EDI to destination              }
        MOV     CH,CL   { Fill EAX with value repeated 4 times  }
        MOV     EAX,ECX
        SHL     EAX,16
        MOV     AX,CX
        MOV     ECX,EDX
        SAR     ECX,2
        JS      @@exit
        REP     STOSD   { Fill count DIV 4 dwords       }
        MOV     ECX,EDX
        AND     ECX,3
        REP     STOSB   { Fill count MOD 4 bytes        }
@@exit:
        POP     EDI
Вот memset от микрософта(CRT Microsoft Visual C++ 6.0)
Код:
public  memset
memset proc
        mov     edx,[esp + 0ch] ; edx = "count"
        mov     ecx,[esp + 4]   ; ecx points to "dst"
        test    edx,edx         ; 0?
        jz      short toend     ; if so, nothing to do
        xor     eax,eax
        mov     al,[esp + 8]    ; the byte "value" to be stored
; Align address on dword boundary
        push    edi             ; preserve edi
        mov     edi,ecx         ; edi = dest pointer
        cmp     edx,4           ; if it's less then 4 bytes
        jb      tail            ; tail needs edi and edx to be initialized
        neg     ecx
        and     ecx,3           ; ecx = # bytes before dword boundary
        jz      short dwords    ; jump if address already aligned
        sub     edx,ecx         ; edx = adjusted count (for later)
adjust_loop:
        mov     [edi],al
        inc     edi
        dec     ecx
        jnz     adjust_loop
dwords:
; set all 4 bytes of eax to [value]
        mov     ecx,eax         ; ecx=0/0/0/value
        shl     eax,8           ; eax=0/0/value/0
        add     eax,ecx         ; eax=0/0val/val
        mov     ecx,eax         ; ecx=0/0/val/val
        shl     eax,10h         ; eax=val/val/0/0
        add     eax,ecx         ; eax = all 4 bytes = [value]
; Set dword-sized blocks
        mov     ecx,edx         ; move original count to ecx
        and     edx,3           ; prepare in edx byte count (for tail loop)
        shr     ecx,2           ; adjust ecx to be dword count
        jz      tail            ; jump if it was less then 4 bytes
        rep     stosd
main_loop_tail:
        test    edx,edx         ; if there is no tail bytes,
        jz      finish          ; we finish, and it's time to leave
; Set remaining bytes
tail:
        mov     [edi],al        ; set remaining bytes
        inc     edi
        dec     edx             ; if there is some more bytes
        jnz     tail            ; continue to fill them
; Done
finish:
        mov     eax,[esp + 8]   ; return dest pointer
        pop     edi             ; restore edi
        ret
toend:
        mov     eax,[esp + 4]   ; return dest pointer
        ret
memset  endp
Если кто-то интересовался проектом Ziron http://codeziron.com/index.php то там в memutils используется memFill — слегка изменённый вариант функции для моей libc(см. выше)
Код:
//******************************************************//
//                                                      //
//     Ziron Run Time Library                           //
//     Ziron Memory Utils (memutils.zir)                //
//                                                      //
//     Copyright (c) 2013-####, OverHertz OOD           //
//                                                      //
//******************************************************//

#ifdef BITS == 32:

#set frame off;

/*
/    Fill block of memory with specified value
/    $buf -- Pointer to block of memory to fill
/    $len -- Number of bytes to set to value
/    $ch_ -- Value to be set
*/
inline function m_memFill($buf, $len, $_ch) {
   // Copyright (c) 0CodErr, KolibriOS team
   using(edi) {
      eax = 0;
      al  = $_ch;
      edx = $len;
      edi = $buf;
      push edi
      ecx = eax;
      ah  = al;
      ch  = cl;
      ecx << 16;
      eax |= ecx;
      ecx = edx;
      ecx >> 2;
      edx &= 3;
      rep stosd;
      ecx = edx;
      rep stosb;
      pop eax
   }
   
   $return eax;
}

function memFill(char* buf; dword len; char ch_) {
   eax = m_memFill(buf, len, ch_);
}


Вернуться к началу
СообщениеДобавлено: Ср июн 06, 2018 11:42 pm 
Не в сети
Аватара пользователя

Зарегистрирован: Пн ноя 19, 2012 5:22 pm
Сообщения: 453
В простейшем случае, если надо очистить первые 256 байтов( или другое кратное 4 число):
xor eax,eax ; так обнулил eax. Нужно всё зачистить не нулями, а другим число(напр. 0х13) - пишем mov eax,0x13131313
mov edi,my_mem ;та память, которую очистим
mov ecx, 256/4 ; - тут количество байтов, делённо на 4 - для скорости очищаем сразу по 4 байта
rep stosd
Если уж очень надо очистить именно 255, то или меняем stosd на stosb( ну и в ecx уже пишем 255, без всякого деления), или усложняем код: зачищаем первые 252 байта с помощью stosd, потом дочищаем stosb. На практике так делать стоит, если у нас десяток килобайт чистится.

_________________
Чем больше сыра, тем больше в нём дыр. Чем больше дыр, тем меньше в нём собственно сыра. Значит, чем больше сыра, тем меньше сыра!


Вернуться к началу
Показать сообщения за:  Поле сортировки  
Начать новую тему  Ответить на тему  [ 7 сообщений ] 

Часовой пояс: UTC+03:00


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Limited
Русская поддержка phpBB