Board.KolibriOS.org

Official KolibriOS board
It is currently Tue May 21, 2019 3:51 pm

All times are UTC+03:00




Post new topic  Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Wed Jun 06, 2018 12:50 pm 
Offline

Joined: Mon Dec 05, 2016 11:04 am
Posts: 132
в IRC-клиенте есть 2048-байтовый массив для хранения команд юзера:
Code:
MAX_COMMAND_LEN = 512
user_command rb MAX_COMMAND_LEN*4
в дальнейшем я пытаюсь очистить хотя бы первые 255 байт для начала, при помощи новой функции:
(в главном файле объявлен счётчик цикла "counter db 0")
Code:
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 ) при выводе на печать я по-прежнему вижу неочищенное начало старой команды юзера.
Что я делаю не так?


Top
   
PostPosted: Wed Jun 06, 2018 2:03 pm 
Offline

Joined: Wed Mar 26, 2008 12:44 pm
Posts: 225
floppy121 wrote:
Что я делаю не так?

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

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

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

Code:
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 байта за цикл).


Top
   
PostPosted: Wed Jun 06, 2018 2:42 pm 
Offline

Joined: Mon Dec 05, 2016 11:04 am
Posts: 132
tsdima wrote:
- или по сумме фиксированного значения и регистра mov byte[user_command][eax], 0

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

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


Top
   
PostPosted: Wed Jun 06, 2018 3:25 pm 
Offline

Joined: Wed Mar 26, 2008 12:44 pm
Posts: 225
floppy121 wrote:
К сожалению именно этот, самый нужный пример, не собирается

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


Top
   
PostPosted: Wed Jun 06, 2018 4:06 pm 
Offline

Joined: Mon Dec 05, 2016 11:04 am
Posts: 132
tsdima wrote:
floppy121 wrote:
К сожалению именно этот, самый нужный пример, не собирается

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

Благодарю, сработало! :P вот что в итоге получилось:
ircc.asm
Code:
MAX_COMMAND_LEN         = 512
MAX_COMMAND_LEN_BYTES   = MAX_COMMAND_LEN*4
userparser.inc
Code:
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


Last edited by floppy121 on Thu Jun 07, 2018 7:14 pm, edited 1 time in total.

Top
   
PostPosted: Wed Jun 06, 2018 6:44 pm 
Offline

Joined: Sun Oct 30, 2011 6:43 pm
Posts: 1499
Можно ещё добавить варианты, используемые в других программах.

Для заполнения области памяти байтами с определённым значением(в том числе нулевым) обычно используется memset.
Вот эта функция в Tiny C Compiler http://websvn.kolibrios.org/filedetails ... memset.asm
Code:
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
Code:
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 использую такой вариант
Code:
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
Code:
{     ->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)
Code:
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(см. выше)
Code:
//******************************************************//
//                                                      //
//     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_);
}


Top
   
PostPosted: Wed Jun 06, 2018 11:42 pm 
Offline
User avatar

Joined: Mon Nov 19, 2012 5:22 pm
Posts: 455
В простейшем случае, если надо очистить первые 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. На практике так делать стоит, если у нас десяток килобайт чистится.

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


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 7 posts ] 

All times are UTC+03:00


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Limited