32位汇编语言学习笔记(43)-- 生成随机数
2015-01-17 07:57
477 查看
此程序出自《Assembly Language step by step programming with linux》第12章,用于演示随机数函数的使用,共涉及两个随机数函数:
void srand( unsigned int seed ); //设置随机数种子
int rand( void ); //获取随机数
先看程序:
程序分析:
pull函数,这个函数有些奇怪,有很多入口,主要用于设置ecx值,最终会跳转到pull。ecx用于控制右移的位数。函数最终目的是生成有位数限制的随机数。
pull31: mov ecx,0 //随机数是31位,不右移
jmp pull
pull16: mov ecx,15 //16位随机数,右移15位
jmp pull
pull8: mov ecx,23 //8位随机数,右移23位
jmp pull
pull7: mov ecx,24 //7位随机数,右移24位
jmp pull
pull6: mov ecx,25 //6位随机数,右移25位
jmp pull
pull4: mov ecx,27 //4位随机数,右移27位
pull: push ecx //保存ecx值
call rand //调用rand函数,生成伪随机数
pop ecx //恢复ecx值
shr eax,cl //返回的随机数值右移cl位
ret
newline函数,用于打印0-10个空行,空行个数由eax来控制。
newline:
mov ecx,10 //ecx=10
sub ecx,eax //ecx = ecx -eax
add ecx,nl //ecx=nl+ecx,nl是一个字节数组的首地址,保存10个换行符
push ecx //保存格式化字符串作为入参
call printf //调用printf函数
add esp,4 //清理调用栈
ret
nl db 10,10,10,10,10,10,10,10,10,10,0
shownums函数用于打印Stash数组中的随机数。
shownums:
mov esi, dword [Pulls] //esi=36
.dorow: mov edi,6 //edi=6
.pushr: dec edi //edi=edi-1
dec esi //esi = esi -1
push dword [Stash+esi*4]//把数组元素压入栈,用于作为printf的入参
cmp edi,0 //edi和0比较
jne .pushr //如果不等于0,跳转到.pushr
push ShowArray //格式化字符串压入栈
call printf //调用printf显示随机数
add esp,28 //清理栈(7个参数)
cmp esi,0 比较esi和0
jnz .dorow //如果不等于0,跳转到.dorow,显示接下来六个随机数
ret
puller用于生成随机数,并把结果保存到Stash数组中
puller:
mov esi,dword [Pulls] //esi = 36
.grab: dec esi //esi = esi -1
call edi //此时edi应该装载的是pull函数的几个入口地址之一,call edi会调用pull函数
mov [Stash+esi*4],eax //保存随机数到Stash[4*esi]数组中
cmp esi,0 //比较esi和0
jne .grab //如果esi不等于0, 跳转,继续循环。
ret
GenAndShowNBitRandom宏,用于生成规定位数的随机数,并打印出显示信息,宏的第一个参数是pull函数的跳转地址,第二个参数是随机数的位数。
%macro GenAndShowNBitRandom 2
mov edi, %1 //edi=pull函数跳转地址,例如pull31
call puller //调用puller函数,生成随机数
push %2 //printf函数的最右一个参数:随机数的位数
push dword [Pulls] //随机数个数
push Display //格式化字符串地址
call printf //调用printf函数,打印随机数概要信息
add esp,12 //清理栈,3个参数
call shownums //打印随机数信息。
%endmacro
主程序:
Seedit: push 0 //timer=0
call time //调用time函数,获取当前时间
add esp,4 //清理栈
push eax //time_t值作为srand函数入参
call srand //调用srand函数,设置随机数种子
add esp,4 //清理栈
GenAndShowNBitRandom pull31,32 //生成并打印32位随机数
GenAndShowNBitRandom pull16,16 //生成并打印16位随机数
GenAndShowNBitRandom pull8,8 //生成并打印8位随机数
GenAndShowNBitRandom pull7,7 //生成并打印7位随机数
GenAndShowNBitRandom pull4,4 //生成并打印4位随机数
Bufclr: mov ecx, BUFSIZE+5 //ecx= BUFSIZE+5
.loop: dec ecx //ecx=ecx-1
mov byte [RandChar+ecx],0 // RandChar[ecx]=0
cmp ecx,0 //比较ecx和0
jnz .loop //如果ecx不等于0,继续循环
Pulchr: mov ebx, BUFSIZE //ebx= BUFSIZE
.loop: dec ebx //ebx= BUFSIZE-1
mov edi,pull6 //edi=pull6,用于生成六位随机数
call puller //调用puller函数,生成六位随机数(0-63)
mov cl,[CharTbl+eax] //cl = CharTbl[eax],使用随机数作为索引获取字母表中的字母,保存到cl中。
mov [RandChar+ebx],cl // RandChar[ebx]=cl
cmp ebx,0 //ebx和0比较
jne .loop //不等于0继续循环,共循环BUFSIZE次。
mov eax,1 //eax=1,要求打印一个换行符
call newline //调用newline函数,打印一个换行符
push RandChar //需要打印的RandChar字符串
call puts //调用puts函数进行打印
add esp,4 //清理栈
mov eax,1 //eax=1,要求打印一个换行符
call newline //调用newline函数,打印一个换行符
makefile文件内容:
测试:
此程序出自《Assembly Language step by step programming with linux》第12章,用于演示随机数函数的使用,共涉及两个随机数函数:
void srand( unsigned int seed ); //设置随机数种子
int rand( void ); //获取随机数
先看程序:
[SECTION .data] ; Section containing initialised data Pulls dd 36 ; How many numbers do we pull? Display db 10,'Here is an array of %d %d-bit random numbners:',10,0 ShowArray db '%10d %10d %10d %10d %10d %10d',10,0 CharTbl db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-@' [SECTION .bss] ; Section containing uninitialized data BUFSIZE equ 70 ; # of randomly chosen chars RandVal resd 1 ; Reserve an integer variable Stash resd 72 ; Reserve an array of 72 integers for randoms RandChar resb BUFSIZE+5 ; Buffer for storing randomly chosen characters [SECTION .text] ; Section containing code extern printf extern puts extern rand extern scanf extern srand extern time pull31: mov ecx,0 ; For 31 bit random, we don't shift jmp pull pull16: mov ecx,15 ; For 16 bit random, shift by 15 bits jmp pull pull8: mov ecx,23 ; For 8 bit random, shift by 23 bits jmp pull pull7: mov ecx,24 ; For 7 bit random, shift by 24 bits jmp pull pull6: mov ecx,25 ; For 6 bit random, shift by 25 bits jmp pull pull4: mov ecx,27 ; For 4 bit random, shift by 27 bits pull: push ecx ; rand trashes ecx; save shift value on stack call rand ; Call rand for random value; returned in EAX pop ecx ; Pop stashed shift value back into ECX shr eax,cl ; Shift the random value by the chosen factor ; keeping in mind that part we want is in CL ret ; Go home with random number in EAX newline: mov ecx,10 ; We need a skip value, which is 10 minus the sub ecx,eax ; number of newlines the caller wants. add ecx,nl ; This skip value is added to the address of push ecx ; the newline buffer nl before calling printf. call printf ; Display the selected number of newlines add esp,4 ; Stack cleanup for one parm ret ; Go home nl db 10,10,10,10,10,10,10,10,10,10,0 shownums: mov esi, dword [Pulls] ; Put pull count into ESI .dorow: mov edi,6 ; Put row element counter into EDI .pushr: dec edi ; Decrement row element counter dec esi ; Decrement pulls counter push dword [Stash+esi*4]; Push number from array onto stack cmp edi,0 ; Have we filled the row yet? jne .pushr ; If not, go push another one push ShowArray ; Push address of base display string call printf ; Display the random numbers add esp,28 ; Stack cleanup: 7 items X 4 bytes = 28 cmp esi,0 ; See if pull count has gone to 0 jnz .dorow ; If not, we go back and do another row! ret ; Done, so go home! puller: mov esi,dword [Pulls] ; Put pull count into ESI .grab: dec esi ; Decrement counter in ESI call edi ; Pull the value; it's returned in eax mov [Stash+esi*4],eax ; Store random value in the array cmp esi,0 ; See if we've pulled 4 yet jne .grab ; Do another if ESI <> 0 ret ; Otherwise, go home! %macro GenAndShowNBitRandom 2 mov edi, %1 ; Copy address of random # subroutine into edi call puller ; Pull as many numbers as called for in [pulls] push %2 ; Size of numbers being pulled, in bits push dword [Pulls] ; Number of random numbers generated push Display ; Address of base display string call printf ; Display the label add esp,12 ; Stack cleanup: 3 parms X 4 bytes = 12 call shownums ; Display the rows of random numbers %endmacro ; MAIN PROGRAM: global main ; Required so linker can find entry point main: push ebp ; Set up stack frame for debugger mov ebp,esp push ebx ; Program must preserve EBP, EBX, ESI, & EDI push esi push edi ;;; Everything before this is boilerplate; use it for all ordinary apps! ; Begin by seeding the random number generator with a time_t value: Seedit: push 0 ; Push a 32-bit null pointer to stack call time ; Returns time_t value (32-bit integer) in EAX add esp,4 ; Stack cleanup for one parm push eax ; Push time_t value in EAX onto stack call srand ; Time_t value is the seed value for random # gen add esp,4 ; Stack cleanup for one parm ; All of the following code blocks are identical except for the size of ; the random value being generated: ; Create and display an array of 31-bit random values GenAndShowNBitRandom pull31,32 ; Create and display an array of 16-bit random values GenAndShowNBitRandom pull16,16 ; Create and display an array of 8-bit random values: GenAndShowNBitRandom pull8,8 ; Create and display an array of 7-bit random values: GenAndShowNBitRandom pull7,7 ; Create and display an array of 4-bit random values: GenAndShowNBitRandom pull4,4 ; Clear a buffer to nulls: Bufclr: mov ecx, BUFSIZE+5 ; Fill whole buffer plus 5 for safety .loop: dec ecx ; BUFSIZE is 1-based so decrement first! mov byte [RandChar+ecx],0 ; Mov null into the buffer cmp ecx,0 ; Are we done yet? jnz .loop ; If not, go back and stuff another null ; Create a string of random alphanumeric characters: Pulchr: mov ebx, BUFSIZE ; BUFSIZE tells us how many chars to pull .loop: dec ebx ; BUFSIZE is 1-based, so decrement first! mov edi,pull6 ; For random in the range 0-63 call puller ; Go get a random number from 0-63 mov cl,[CharTbl+eax] ; Use random # in eax as offset into table ; and copy character from table into CL mov [RandChar+ebx],cl ; Copy char from CL to character buffer cmp ebx,0 ; Are we done having fun yet? jne .loop ; If not, go back and pull another ; Display the string of random characters: mov eax,1 ; Output a newline call newline ; using the newline procedure push RandChar ; Push the address of the char buffer call puts ; Call puts to display it add esp,4 ; Stack cleanup for one parm mov eax,1 ; Output a newline call newline ; using the newline subroutine ;;; Everything after this is boilerplate; use it for all ordinary apps! pop edi ; Restore saved registers pop esi pop ebx mov esp,ebp ; Destroy stack frame before returning pop ebp ret ; Return control to Linux
程序分析:
pull函数,这个函数有些奇怪,有很多入口,主要用于设置ecx值,最终会跳转到pull。ecx用于控制右移的位数。函数最终目的是生成有位数限制的随机数。
pull31: mov ecx,0 //随机数是31位,不右移
jmp pull
pull16: mov ecx,15 //16位随机数,右移15位
jmp pull
pull8: mov ecx,23 //8位随机数,右移23位
jmp pull
pull7: mov ecx,24 //7位随机数,右移24位
jmp pull
pull6: mov ecx,25 //6位随机数,右移25位
jmp pull
pull4: mov ecx,27 //4位随机数,右移27位
pull: push ecx //保存ecx值
call rand //调用rand函数,生成伪随机数
pop ecx //恢复ecx值
shr eax,cl //返回的随机数值右移cl位
ret
newline函数,用于打印0-10个空行,空行个数由eax来控制。
newline:
mov ecx,10 //ecx=10
sub ecx,eax //ecx = ecx -eax
add ecx,nl //ecx=nl+ecx,nl是一个字节数组的首地址,保存10个换行符
push ecx //保存格式化字符串作为入参
call printf //调用printf函数
add esp,4 //清理调用栈
ret
nl db 10,10,10,10,10,10,10,10,10,10,0
shownums函数用于打印Stash数组中的随机数。
shownums:
mov esi, dword [Pulls] //esi=36
.dorow: mov edi,6 //edi=6
.pushr: dec edi //edi=edi-1
dec esi //esi = esi -1
push dword [Stash+esi*4]//把数组元素压入栈,用于作为printf的入参
cmp edi,0 //edi和0比较
jne .pushr //如果不等于0,跳转到.pushr
push ShowArray //格式化字符串压入栈
call printf //调用printf显示随机数
add esp,28 //清理栈(7个参数)
cmp esi,0 比较esi和0
jnz .dorow //如果不等于0,跳转到.dorow,显示接下来六个随机数
ret
puller用于生成随机数,并把结果保存到Stash数组中
puller:
mov esi,dword [Pulls] //esi = 36
.grab: dec esi //esi = esi -1
call edi //此时edi应该装载的是pull函数的几个入口地址之一,call edi会调用pull函数
mov [Stash+esi*4],eax //保存随机数到Stash[4*esi]数组中
cmp esi,0 //比较esi和0
jne .grab //如果esi不等于0, 跳转,继续循环。
ret
GenAndShowNBitRandom宏,用于生成规定位数的随机数,并打印出显示信息,宏的第一个参数是pull函数的跳转地址,第二个参数是随机数的位数。
%macro GenAndShowNBitRandom 2
mov edi, %1 //edi=pull函数跳转地址,例如pull31
call puller //调用puller函数,生成随机数
push %2 //printf函数的最右一个参数:随机数的位数
push dword [Pulls] //随机数个数
push Display //格式化字符串地址
call printf //调用printf函数,打印随机数概要信息
add esp,12 //清理栈,3个参数
call shownums //打印随机数信息。
%endmacro
主程序:
Seedit: push 0 //timer=0
call time //调用time函数,获取当前时间
add esp,4 //清理栈
push eax //time_t值作为srand函数入参
call srand //调用srand函数,设置随机数种子
add esp,4 //清理栈
GenAndShowNBitRandom pull31,32 //生成并打印32位随机数
GenAndShowNBitRandom pull16,16 //生成并打印16位随机数
GenAndShowNBitRandom pull8,8 //生成并打印8位随机数
GenAndShowNBitRandom pull7,7 //生成并打印7位随机数
GenAndShowNBitRandom pull4,4 //生成并打印4位随机数
Bufclr: mov ecx, BUFSIZE+5 //ecx= BUFSIZE+5
.loop: dec ecx //ecx=ecx-1
mov byte [RandChar+ecx],0 // RandChar[ecx]=0
cmp ecx,0 //比较ecx和0
jnz .loop //如果ecx不等于0,继续循环
Pulchr: mov ebx, BUFSIZE //ebx= BUFSIZE
.loop: dec ebx //ebx= BUFSIZE-1
mov edi,pull6 //edi=pull6,用于生成六位随机数
call puller //调用puller函数,生成六位随机数(0-63)
mov cl,[CharTbl+eax] //cl = CharTbl[eax],使用随机数作为索引获取字母表中的字母,保存到cl中。
mov [RandChar+ebx],cl // RandChar[ebx]=cl
cmp ebx,0 //ebx和0比较
jne .loop //不等于0继续循环,共循环BUFSIZE次。
mov eax,1 //eax=1,要求打印一个换行符
call newline //调用newline函数,打印一个换行符
push RandChar //需要打印的RandChar字符串
call puts //调用puts函数进行打印
add esp,4 //清理栈
mov eax,1 //eax=1,要求打印一个换行符
call newline //调用newline函数,打印一个换行符
makefile文件内容:
randtest: randtest.o gcc randtest.o -o randtest randtest.o: randtest.asm nasm -f elf -F stabs randtest.asm
测试:
[root@bogon randtest]# make nasm -f elf -F stabs randtest.asm gcc randtest.o -o randtest [root@bogon randtest]# ./randtest Here is an array of 36 32-bit random numbners: 783082802 2015556527 543193849 2039226355 941006786 31398675 1774612191 1481082542 470873846 116734738 14801476 962009402 288935524 784925144 2104709381 1237311754 601393386 1134661054 1752141735 528512928 848300003 858978037 1617820568 623786287 291301057 1585022978 84190193 1438304756 1614336276 950412687 1100380723 12131855 632155963 1232307843 1616421653 740413255 Here is an array of 36 16-bit random numbners: 13695 44098 46752 34032 29728 43189 56002 11884 7596 32048 13189 35372 55967 56808 42628 39838 30920 16414 22532 22846 8920 39697 20276 30563 6695 64733 55417 6325 45441 17810 14986 23603 57495 36424 42387 23462 Here is an array of 36 8-bit random numbners: 156 4 147 110 230 22 243 234 9 21 68 110 155 132 127 66 98 228 73 162 240 77 202 215 75 223 152 239 254 10 54 136 65 50 245 211 Here is an array of 36 7-bit random numbners: 50 0 121 61 123 110 38 49 20 99 114 115 92 21 8 11 29 98 75 103 37 92 26 45 10 113 100 70 80 75 6 89 60 5 95 127 Here is an array of 36 4-bit random numbners: 5 12 10 15 9 13 11 9 0 8 8 15 11 3 7 15 15 12 4 9 9 6 13 1 11 1 11 0 9 11 0 9 11 4 15 12 @G8iqJJt12Oh8FKKEINTmIvq6ag7RXTAU5TkF9xJ3GaZBkMPiRU7jzFMxKmfhqhySz9Xt7
相关文章推荐
- windows下32位汇编语言学习笔记 第十章 内存管理部分 1
- 32位汇编语言学习笔记(4)--移位操作
- 32位汇编语言学习笔记(9)--分析while循环的汇编代码
- 32位汇编语言学习笔记(8)--分析do-while循环的汇编代码
- 32位汇编语言学习笔记(20)--栈破坏检测
- windows下32位汇编语言学习笔记 第十章 内存管理部分 2
- 32位汇编语言学习笔记(12)--分析switch语句的汇编代码
- 32位汇编语言学习笔记(17)--结构体
- windows下32位汇编语言学习笔记
- 32位汇编语言学习笔记(15)--定长数组
- windows下32位汇编语言学习笔记
- windows下32位汇编语言学习笔记
- 32位汇编语言学习笔记(6)--设置条件码
- 32位汇编语言学习笔记(18)--联合
- windows下32位汇编语言学习笔记 第四章 第一个窗口程序 (windows的消息机制)
- 32位汇编语言学习笔记(3)--leal和算术运算指令
- 32位汇编语言学习笔记(5)--特殊的算术操作
- 32位汇编语言学习笔记(1)--简单示例
- 32位汇编语言学习笔记(16)--变长数组
- 32位汇编语言学习笔记(13)--函数的调用