我必须编写一个汇编程序,它将调用外部汇编文件来生成用户指定的素数。现在我想生成小于10的素数,然后将其报告回屏幕,并稍后担心用户输入。 genprimes.asm中的代码将正确生成素数并将它们存储到数组中。我想将它们推入堆栈(参见genprimes.asm中的第79行),并在从seive.asm中调用该函数返回后恢复它们。我的代码在genprimes.asm中工作,如果我注释掉" push ecx;"在第79行.sieve.asm在第32行中断,这是代码"调用genPrimes"。我试着在" genprimes.asm"中逐步完成我的所有代码。我得到了return语句,然后visual studio说我无法进一步调试,因为它不支持跳回主文件。我不知道为什么这会破裂。我怎样才能将我的素数带回主文件" sieve.asm"我打电话给#34; genprimes.asm"从?
sieve.asm:
.586
.MODEL FLAT
INCLUDE io.h
EXTERN GenPrimes2:PROC
PUBLIC genPrimes
.STACK 4096 ; reserve 4096-byte stack
.DATA ; reserve storage for data
count DWORD ?
sieve BYTE 10000 DUP(1)
string BYTE 40 DUP (?)
prompt1 BYTE "Enter number of primes: ", 0
prompt2 BYTE "prime number: ", 0
primenum BYTE 11 DUP (?), 0
.CODE
genPrimes PROC
; push ebp ; save base pointer
; mov ebp, esp ; establish stack frame
; push ebx
; CODE
call GenPrimes2 ;*** breaks here ***
; pop ebx
; pop ebp
ret ;exit genPrimes
genPrimes ENDP
_sieve PROC ; start of sieve program code
input prompt1, string, 40 ; read ASCII characters
call genPrimes
output prompt2, primenum ; output label and sum
mov eax, 0 ; exit with return code 0
ret
_sieve ENDP
END
genprimes.asm:
.586
.MODEL FLAT
.STACK 4096
n=10
.data
prime DWORD n DUP(?)
.code
GenPrimes2 PROC
mov ebx, 4
mov ecx, 0
loopArray:
inc ecx
mov prime[ebx], ecx
add ebx, 4
cmp ecx, n
jb loopArray
mov eax, 3
mov ebx, 2
mov edx, 0
mov ecx,3
sieve_loop:
cmp eax,ebx
je skip
mov edx, 0 ;zero out remainder
div ebx
cmp edx,0 ; if remainder 0, not a prime
je NotPrime ;Jump if is a factor, since it cant be prime
; compare eax with n, if equal increment ebx
cmp ecx,n
jge incrementEbx
; compare ebx with n, if equal end sieve
cmp ebx, n
je sieve_end
inc ecx
mov eax, ecx
jmp sieve_loop
skip:
inc eax
jmp sieve_loop
NotPrime:
mov eax, ecx ; store count in eax
imul ecx, 4
mov prime[ecx],0
mov ecx, eax
inc ecx ; increment ecx count
inc eax ; increment eax divisor
jmp sieve_loop
incrementEbx:
inc ebx
mov eax, 3 ; dividend
mov ecx, 3 ; counter
jmp sieve_loop
sieve_end:
mov ebx, 4
mov eax, 0
; ************* Add break point on print loop, ecx will be loading with primes and 0's ********************
; ************* All non-prime numbers have been changed to a 0 ********************
PrintLoop:
mov ecx, prime[ebx] ; Prime numbers are the non-zeros in this Array
push ecx ; **This is somehow breaking it, but doesnt throw and error
;** when steeping through in Visual Studio?!?
add ebx, 4
cmp ebx, 40
jb PrintLoop
mov eax, 0 ; exit with return code 0
ret
GenPrimes2 ENDP
END
答案 0 :(得分:4)
推送ecx指令会使您的堆栈失去平衡。没有相应的流行音乐。您将返回到从ecx推送的最后一个值而不是返回地址给出的地址。您需要弹出所推动的内容或将sp保存在条目中并在退出返回之前将其恢复。
答案 1 :(得分:1)
您需要了解调用约定。
简而言之:当你执行call
时,下一条指令的IP被放入堆栈。 ret
将从堆栈顶部获取地址,并将该地址移至该地址。
但您正在推动PUSH CX
,因此ret
会找到错误的返回地址。通常您返回AX(作为返回值)或将数据放在返回地址之前。这应该从调用者设置。
答案 2 :(得分:0)
有几种不同的方法可以从数组中的函数返回信息。
这些方法中的每一种都有利有弊。例如,使用选项3,调用者必须知道在完成数组操作时它负责释放数组。
在您的情况下,由于调用者将指定它想要生成多少个值,因此选项1可能是最好的。如果只有被调用的函数知道它想要返回多少项,则选项3或4通常是最好的。
有关利弊的更多详情:
选项1:来电者必须知道要预留多少空间。如果没有足够的空间,则该函数必须返回错误或指示有更多项目。一个例子是sprintf。
选项2:当需要的空间量固定时,这可能是一个不错的选择。但调用者必须知道,如果它调用该函数两次,则会覆盖第一个值。一个例子是C库函数ctime,它总是返回一个固定长度的字符串。
选项3:调用者必须知道它负责在完成数组时释放数组,并且它需要使用相同的分配器来释放数组作为用于分配它的函数。这方面的一个例子是strdup。
选项4:如果您使用支持它的语言,这通常是最佳选择。对于汇编语言编程,实现它的基础结构可能过于复杂,除非在整个项目中使用它足以使其值得。