此程序出自《Assembly Language step by step programming with linux》第12章,用于演示随机数函数的使用,共涉及两个随机数函数:
void srand( unsigned int seed ); //设置随机数种子
int rand( void ); //获取随机数

先看程序:

[SECTION .data]          ; Section containing initialised dataPulls     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 dataBUFSIZE  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 codeextern printf
extern puts
extern rand
extern scanf
extern srand
extern time         pull31: mov ecx,0       ; For 31 bit random, we don't shiftjmp pull
pull16: mov ecx,15      ; For 16 bit random, shift by 15 bitsjmp pull
pull8:  mov ecx,23      ; For 8 bit random, shift by 23 bitsjmp pull
pull7:  mov ecx,24      ; For 7 bit random, shift by 24 bitsjmp pull
pull6:  mov ecx,25      ; For 6 bit random, shift by 25 bitsjmp pull
pull4:  mov ecx,27      ; For 4 bit random, shift by 27 bits
pull:   push ecx        ; rand trashes ecx; save shift value on stackcall rand      ; Call rand for random value; returned in EAXpop ecx            ; Pop stashed shift value back into ECXshr eax,cl       ; Shift the random value by the chosen factor;  keeping in mind that part we want is in CLret           ; Go home with random number in EAXnewline:mov ecx,10   ; We need a skip value, which is 10 minus thesub ecx,eax    ;  number of newlines the caller wants.add ecx,nl   ; This skip value is added to the address ofpush ecx    ;  the newline buffer nl before calling printf.call printf  ; Display the selected number of newlinesadd esp,4  ; Stack cleanup for one parmret     ; Go home
nl  db 10,10,10,10,10,10,10,10,10,10,0shownums: 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 counterdec esi          ; Decrement pulls counterpush dword [Stash+esi*4]; Push number from array onto stackcmp edi,0      ; Have we filled the row yet?jne .pushr     ; If not, go push another onepush ShowArray     ; Push address of base display stringcall printf        ; Display the random numbersadd esp,28      ; Stack cleanup: 7 items X 4 bytes = 28cmp esi,0       ; See if pull count has gone to 0jnz .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 ESIcall edi      ; Pull the value; it's returned in eaxmov [Stash+esi*4],eax   ; Store random value in the arraycmp esi,0      ; See if we've pulled 4 yetjne .grab       ; Do another if ESI <> 0 ret          ; Otherwise, go home!%macro GenAndShowNBitRandom 2  mov edi, %1 ; Copy address of random # subroutine into edicall puller   ; Pull as many numbers as called for in [pulls]             push %2     ; Size of numbers being pulled, in bitspush dword [Pulls] ; Number of random numbers generatedpush Display  ; Address of base display stringcall printf ; Display the labeladd esp,12   ; Stack cleanup: 3 parms X 4 bytes = 12call shownums   ; Display the rows of random numbers
%endmacro  ; MAIN PROGRAM:global main           ; Required so linker can find entry pointmain:push ebp      ; Set up stack frame for debuggermov ebp,esppush ebx        ; Program must preserve EBP, EBX, ESI, & EDIpush esipush 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 stackcall time  ; Returns time_t value (32-bit integer) in EAXadd esp,4 ; Stack cleanup for one parmpush eax    ; Push time_t value in EAX onto stackcall srand ; Time_t value is the seed value for random # genadd 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 valuesGenAndShowNBitRandom pull31,32; Create and display an array of 16-bit random valuesGenAndShowNBitRandom 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 buffercmp 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-63call puller       ; Go get a random number from 0-63mov cl,[CharTbl+eax] ; Use random # in eax as offset into table;  and copy character from table into CLmov [RandChar+ebx],cl    ; Copy char from CL to character buffercmp 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 newlinecall newline  ;  using the newline procedurepush RandChar ; Push the address of the char buffer call puts ; Call puts to display itadd esp,4  ; Stack cleanup for one parmmov eax,1   ; Output a newlinecall newline  ;  using the newline subroutine;;; Everything after this is boilerplate; use it for all ordinary apps!pop edi       ; Restore saved registerspop esipop ebxmov esp,ebp  ; Destroy stack frame before returningpop ebpret        ; 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.ogcc randtest.o -o randtest
randtest.o: randtest.asmnasm -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  962009402288935524  784925144 2104709381 1237311754  601393386 1134661054
1752141735  528512928  848300003  858978037 1617820568  623786287291301057 1585022978   84190193 1438304756 1614336276  950412687
1100380723   12131855  632155963 1232307843 1616421653  740413255Here is an array of 36 16-bit random numbners:13695      44098      46752      34032      29728      4318956002      11884       7596      32048      13189      3537255967      56808      42628      39838      30920      1641422532      22846       8920      39697      20276      305636695      64733      55417       6325      45441      1781014986      23603      57495      36424      42387      23462Here is an array of 36 8-bit random numbners:156          4        147        110        230         22243        234          9         21         68        110155        132        127         66         98        22873        162        240         77        202        21575        223        152        239        254         1054        136         65         50        245        211Here is an array of 36 7-bit random numbners:50          0        121         61        123        11038         49         20         99        114        11592         21          8         11         29         9875        103         37         92         26         4510        113        100         70         80         756         89         60          5         95        127Here is an array of 36 4-bit random numbners:5         12         10         15          9         1311          9          0          8          8         1511          3          7         15         15         124          9          9          6         13          111          1         11          0          9         110          9         11          4         15         12@G8iqJJt12Oh8FKKEINTmIvq6ag7RXTAU5TkF9xJ3GaZBkMPiRU7jzFMxKmfhqhySz9Xt7

32位汇编语言学习笔记(43)-- 生成随机数相关推荐

  1. 32位汇编语言学习笔记(45)--测试简单文件操作接口(完)

     这是<Assembly Language step by step programming with linux>书中的最后一个程序,也是全书中的最复杂的一个程序. 首先看一下这个程 ...

  2. windows下32位汇编语言学习笔记

    windows下32位汇编语言学习笔记 第一章  第一章 背景知识 80x86处理器的存储器 4个数据寄存器 EAX,EBX,ECX,EDX EAX寄存器 所有API函数的返回值都保存在EAX里,注意 ...

  3. 32位汇编语言学习笔记(33)--aaa指令

     aaa(ASCII adjust after addition)指令,是BCD指令集中的一个指令,用于在两个未打包的BCD值相加后,调整al和ah寄存器的内容. BCD(Binary-coded ...

  4. 32位汇编语言学习笔记(36)--repne scasb指令

     repne scasb指令,用于扫描字符串,计算字符串的长度,如下两条指令: cld repne scasb 对应的等价指令是: scans:inc edi     dec ecx     je ...

  5. R语言学习笔记:生成随机数

    R语言中,可以根据不同的分布生成随机数 均匀分布 runif(par1) runif(par1, min = par2, max = par3) 我们需要输入3个参数: par1:生成随机数的个数 p ...

  6. 16位汇编语言学习笔记(2)—— 汇编程序设计

    文章目录 4. 顺序程序设计 4.1 十进制的算数运算 4.2 输入输出功能调用 4.3 综合案例 5. 分支程序设计 5.1 转移指令 5.1.1 条件转移指令 单标志条件转移指令 无符号数专用条件 ...

  7. 16位汇编语言学习笔记(1)——基础知识

    文章目录 1.配置汇编学习环境 1.1 工具下载 1.2 配置环境 2. 汇编命令基础 2.1 简单使用 2.2 常用命令 3. 汇编语言基础 3.1 汇编语言程序与汇编程序 3.2 汇编语言程序的格 ...

  8. Python学习笔记(四)—生成随机数

    函数randint(a,b)可以产生区间(a,b)中的随机数.但是要加import random: 比如说: import random number1 = random.randint(0,9) n ...

  9. Flutter学习笔记之生成随机数

    函数:Random 写法: //生成100以内随机数 var a = Random().nextInt(100); //生成0至1之间的随机数 var a = Random().nextDouble( ...

最新文章

  1. 《LeetCode力扣练习》第19题 删除链表的倒数第 N 个结点 Java
  2. 笔试算法题及解答(Python)
  3. 别再说找不到Python练手项目了,这80个拿去过冬
  4. Java易混小知识——equals方法和==的区别
  5. 2019.7.20十道js题目
  6. Handler 消息传递机制
  7. Go语言核心之美 3.5-JSON
  8. ps显示暂存盘已满的解决办法
  9. 【无标题】关于BC25连接电信物联网平台的问题(批量产品在广东连接不到物联网平台,在合肥测试是可以的)
  10. 工银亚洲见证开户详细过程和攻略
  11. 2380318-57-8,Thalidomide-O-PEG4-Azide通过点击化学与炔烃或DBCO、BCN连接的分子反应的PROTAC连接物
  12. JSP 和 JavaBean 来实现一个简易计算器
  13. PTG DAO 生态
  14. cesium创建、添加json数据
  15. POJ - 1737 Connected Graph,Java(计数类DP)
  16. ASCII码中不同字符分类、含义及相关技巧
  17. ElasticSearch实战(七)-BKD-Tree 多维空间树算法(范围查询算法)
  18. echarts环形图内部圆,外部圆形以及阴影设置
  19. Python人工智能
  20. 使用GPU版PYtorch,踩过的坑(PYtorch版本和GPU版本不对应问题)

热门文章

  1. AtCoder - 2365 Camel and Oases
  2. Basler 多个网口相机出图(SDK版)
  3. 判断手机屏幕是否旋转
  4. JS中的跨域问题及解决办法汇总
  5. 好莱坞首部全亚裔主演电影上映,华人终于谈恋爱了
  6. u盘安装计算机系统,U盘系统_详细教您将系统安装到U盘
  7. 归一化数字角频率_说一说信号与系统中的“归一化处理“
  8. Android开发插件推荐一:Lombok
  9. SE14激活并调整数据库时报数据库对象不一致错误
  10. 前端js 下载xls表格