генерация рандомных чисел и запись их в файл в ассемблере

У меня есть программа, в которой я создаю нужный мне файл file.dat, и дальше хочу записать туда 20 рандомных чисел. Пока что я только создал файл и в цикле у меня успешно генерируются числа которые по очереди каждый раз возвращаются в регистр eax. И я знаю, что при записи в файл мне нужен будет какой то например bufforNumbers, в котором будут записаны все цифры, так вот, как мне в эту переменную записать все 20 чисел, что бы каждая предыдущая сохранялась в переменной. Вот мой код сейчас:

.586P
.MODEL flat, STDCALL
;--- stale z pliku .\include\windows.inc ---
STD_INPUT_HANDLE                     equ -10
STD_OUTPUT_HANDLE                    equ -11
GENERIC_READ                         equ 80000000h
GENERIC_WRITE                        equ 40000000h
CREATE_NEW                           equ 1
CREATE_ALWAYS                        equ 2
OPEN_EXISTING                        equ 3
OPEN_ALWAYS                          equ 4
TRUNCATE_EXISTING                    equ 5
FILE_FLAG_WRITE_THROUGH              equ 80000000h
FILE_FLAG_OVERLAPPED                 equ 40000000h
FILE_FLAG_NO_BUFFERING               equ 20000000h
FILE_FLAG_RANDOM_ACCESS              equ 10000000h
FILE_FLAG_SEQUENTIAL_SCAN            equ 8000000h
FILE_FLAG_DELETE_ON_CLOSE            equ 4000000h
FILE_FLAG_BACKUP_SEMANTICS           equ 2000000h
FILE_FLAG_POSIX_SEMANTICS            equ 1000000h
FILE_ATTRIBUTE_READONLY              equ 1h
FILE_ATTRIBUTE_HIDDEN                equ 2h
FILE_ATTRIBUTE_SYSTEM                equ 4h
FILE_ATTRIBUTE_DIRECTORY             equ 10h
FILE_ATTRIBUTE_ARCHIVE               equ 20h
FILE_ATTRIBUTE_NORMAL                equ 80h
FILE_ATTRIBUTE_TEMPORARY             equ 100h
FILE_ATTRIBUTE_COMPRESSED            equ 800h
FORMAT_MESSAGE_ALLOCATE_BUFFER       equ 100h
FORMAT_MESSAGE_IGNORE_INSERTS        equ 200h
FORMAT_MESSAGE_FROM_STRING           equ 400h
FORMAT_MESSAGE_FROM_HMODULE          equ 800h
FORMAT_MESSAGE_FROM_SYSTEM           equ 1000h
FORMAT_MESSAGE_ARGUMENT_ARRAY        equ 2000h
FORMAT_MESSAGE_MAX_WIDTH_MASK        equ 0FFh
FILE_BEGIN                           equ 0h ;MoveMethod dla SetFilePointe
FILE_CURRENT                         equ 1h ;MoveMethod dla SetFilePointe
FILE_END                             equ 2h ;MoveMethod dla SetFilePointe

;--- funkcje API Win32 z pliku  .\include\user32.inc ---
CharToOemA PROTO :DWORD,:DWORD
;--- z pliku .\include\kernel32.inc ---
GetStdHandle PROTO :DWORD
ReadConsoleA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
WriteConsoleA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
ExitProcess PROTO :DWORD
wsprintfA PROTO C :VARARG     ;; int wsprintf(LPTSTR lpOut,// pointer to buffer for output 
                              ;; LPCTSTR lpFmt,// pointer to format-control string 
                              ;;    ... // optional arguments  );
lstrlenA PROTO :DWORD
GetCurrentDirectoryA PROTO :DWORD,:DWORD  
      ;;nBufferLength, lpBuffer; zwraca length
CreateDirectoryA PROTO :DWORD,:DWORD      
      ;;lpPathName, lpSecurityAttributes; zwraca 0 jeœli b³ad
lstrcatA PROTO :DWORD,:DWORD              
      ;; lpString1, lpString2; zwraca lpString1
CreateFileA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD 
      ;; LPCTSTR lpszName, DWORD fdwAccess, 
      ;; DWORD fdwShareMode, LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate, 
      ;; DWORD fdwAttrsAndFlags, HANDLE hTemplateFile
lstrcpyA PROTO :DWORD,:DWORD  
      ;;LPTSTR lpString1 // address of buffer, LPCTSTR lpString2    // address of string to copy 
CloseHandle PROTO :DWORD      
      ;; BOOL CloseHandle(HANDLE hObject)
WriteFile PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD    
   ;; BOOL WriteFile(
   ;; HANDLE hFile, // handle to file to write to
   ;; LPCVOID lpBuffer, // pointer to data to write to file
   ;; DWORD nNumberOfBytesToWrite,  // number of bytes to write
   ;; LPDWORD lpNumberOfBytesWritten,   // pointer to number of bytes written
   ;; LPOVERLAPPED lpOverlapped     // pointer to structure needed for overlapped I/O 
   ;;);
ReadFile PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
    ;;BOOL ReadFile(
    ;;HANDLE hFile, // handle of file to read 
    ;;LPVOID lpBuffer,  // address of buffer that receives data  
    ;;DWORD nNumberOfBytesToRead,   // number of bytes to read 
    ;;LPDWORD lpNumberOfBytesRead,  // address of number of bytes read 
    ;;LPOVERLAPPED lpOverlapped     // address of structure for data 
    ;;);
CopyFileA PROTO :DWORD,:DWORD,:DWORD      
    ;; BOOL CopyFile(
    ;;LPCTSTR lpExistingFileName,   // pointer to name of an existing file 
    ;;LPCTSTR lpNewFileName,    // pointer to filename to copy to 
    ;;BOOL bFailIfExists    // flag for operation if file exists  
    ;;);
GetLastError PROTO

GetTickCount PROTO
;--- z pliku ..\include\masm32.inc ---
nseed PROTO :DWORD
nrandom PROTO :DWORD


dwtoa PROTO dwValue:DWORD, lpBuffer:DWORD ;dwtoa convert a DWORD value to an ascii string.
;dwtoa proc dwValue:DWORD, lpBuffer:DWORD   
atodw  PROTO lpBuffer:DWORD ;atodw converts a decimal string to dword.
;atodw proc String:PTR BYTE
StripLF PROTO :DWORD ;StripLF is designed to remove the CRLF (ascii 13,10) by writing an ascii zero in the place of the first occurrence of ascii 13.
;StripLF proc strng:DWORD
StdIn PROTO :DWORD,:DWORD ;StdIn receives text input from the console and places it in the buffer required as a parameter. The function terminates when Enter is pressed.
;StdIn proc lpszBuffer:DWORD,bLen:DWORD
StdOut PROTO :DWORD ;StdOut will display a zero terminated string at the current position in the console.
;StdOut proc lpszText:DWORD
;--- funkcje
;------------s
;includelib .\lib\user32.lib
;includelib .\lib\kernel32.lib
;includelib .\lib\masm32.lib
;-------------
_DATA SEGMENT

    folderName BYTE "/newFolder", 0
    fileName BYTE "/file.dat", 0
    buffor BYTE 250 dup(0)

    randomNumber DD ?
    bufforNumbers DD 250 dup(0)

_DATA ENDS
;------------
_TEXT SEGMENT
main proc

; -- creating folder "newFolder" --
    push OFFSET buffor
    push 255
    call GetCurrentDirectoryA

    push OFFSET folderName
    push OFFSET buffor
    call lstrcatA

    push 0
    push OFFSET buffor
    call CreateDirectoryA
; -- end --

; -- creating file "file.dat" --
    push OFFSET buffor
    push 255
    call GetCurrentDirectoryA

    push OFFSET fileName
    push OFFSET buffor
    call lstrcatA

    push 0
    push 0
    push CREATE_ALWAYS
    push 0
    push 0
    push GENERIC_WRITE
    push OFFSET buffor
    call CreateFileA
; -- end --

; -- generating random numbers --
    call GetTickCount
    push eax 
    call nseed

    mov ecx, 20
    generateRandomNumbers:
    push ecx

    ;--- generating random numbers from 0 to 99 ---
        push 99
        call nrandom
        mov bufforNumbers, eax 

    pop ecx
    loop generateRandomNumbers
; -- end -- 

    push 0
    call ExitProcess
main endp
_TEXT   ENDS
END

Ответы (2 шт):

Автор решения: Илья К

Сбрось все числа в стек и получишь "временную" строку, а потом передай указатель на нее в функцию записи в файл.

→ Ссылка
Автор решения: PRODIGY

В вашем коде 90% лишнего. Если вы получаете рандом тиками, тогда лучше заменить вызов функции на инструкцию RDTSC, которая подразумевает "Read Time Stamp Counter", т.е. по сути делает то-же самое. Эта инструкция возвращает 64-бит тики в пару EDX:EAX. Обычно старшая часть счётчика в EDX переполняется долго, зато младшую часть в EAX вполне можно использовать как пародию на рандом. Чтобы увеличить рассеиваемость, можно в цикле крутить биты внутри регистра посредством ROL, а в качестве счётчика сдвигов задействовать сам-же счётчик цикла. Примитивно работать с файлами удобно через группу функций _lcreate() из kernel32.dll - они поддерживаются вплоть до систем х86-64 Win7-10.

Вот пример вашей задачи на FASM'e. Здесь инструкция stosd сама сдвигает указатель в EDI, а loop привязана к счётчику в ЕСХ, и на каждой итерации авто-уменьшает его на 1. Цикл будет продолжаться, пока ECX не станет нуль:

include 'win32ax.inc'
.data
buff   rd   20     ;// приёмный буфер в 20 двойных слов

.code
start:  
;// Генерим рандомы и сбрасываем их в буфер
        mov     edi,buff    ;// EDI = адрес приёмника для STOSD
        mov     ecx,20      ;// ECX = счётчик цикла + маска сдвига рандома
@rnd:   rdtsc               ;// EAX = тики счётчика TSC 
        rol     eax,cl      ;// прокрутим значение-рандом по внешнему счётчику
        stosd               ;// записать EAX в буфер!
        loop    @rnd        ;// промотать цикл ECX-раз...

;// Создаём файл и записываем в него данные из буфера
        invoke  _lcreat,<'file.dat',0>,0
        push    eax
        invoke  _lwrite,eax,buff,20*4
        pop     eax
        invoke  _lclose,eax

;// GAME over!
        invoke  ExitProcess,0
.end start
→ Ссылка