我必须使用汇编语言绘制简单的余弦(x)波。我按照教授的指示完成了项目的所有步骤,但我无法正确打印程序。这是我得到的输出,
linux2[14]% cat plot4.out
*****************************************
但应该是......
*****
* *
* *
* *
* *
* *
* *
* *
* *
* *
* *
* *
* *
* *
* *
** **
** **
这是我的代码。任何帮助将不胜感激。
SECTION .data ; Data section, initialized variables
nrow: dq 21 ; 21 rows
ncol: dq 41 ; 41 columns
fmtc: db "%c", 0 ; print one character at a time
fmtend: db 10, 0 ; end a line
star: db '*' ; one character '*'
fmtendLen: equ $-fmtend
pStar: db "*"
starLen: equ $-pStar
pSpace: db " "
spaceLen: equ $-pSpace
len: equ $-star
spc: db ' '
af: dq 1.0, 0.0, -0.5 ; coefficients of polynomial, a_0 first
dq 0.0, 0.041667, 0.0, -0.001389, 0.0, 0.000025
XF: dq 0.0 ; computed
Y: dq 0.0 ; computed
N: dq 8 ; power of polynomial
X0: dq -3.14159 ; start XF
DX0: dq 0.15708 ; increment for XF ncol-1 times
one: dq 1.0
ten: dq 10.0
none: dq -1.0
nten: dq -10.0
twenty: dq 20.0
zero: dq 0.0
newline: db 10
section .bss
a2: resb 21*41 ; two dimensional array of bytes
i: resq 1 ; row subscript
j: resq 1 ; col subscript
k: resq 1
SECTION .text ; Code section.
global _start ; the standard gcc entry point
_start: ; the program label for the entry point
;;; clear a2 to space
mov rax,0 ; i=0
mov [i],rax
loopi:
mov rax,[i]
mov rbx,0 ; j=0
mov [j],rbx
loopj:
mov rax,[i]
mov rbx,[j]
imul rax,[ncol] ; i*ncol
add rax, rbx ; i*ncol + j
mov dl, [spc] ; need just character, byte
mov [a2+rax],dl ; store space
mov rbx,[j]
inc rbx ; j++
mov [j],rbx
cmp rbx,[ncol] ; j<ncol
jne loopj
mov rax,[i]
inc rax ; i++
mov [i],rax
cmp rax,[nrow] ; i<ncol
jne loopi
;;; end clear a2 to space
mov rax, 0 ;i = 0
mov [i], rax
mov rbx, 0 ;j = 0
mov [j], rbx
cos:
mov rcx,[N] ; loop iteration count initialization, n
fld qword [af+8*rcx] ; accumulate value here, get coefficient a_
h5loop:
fmul qword [XF] ; * XF
fadd qword [af+8*rcx-8] ; + aa_n-i
loop h5loop ; decrement rcx, jump on non zero
fstp qword [Y] ; store Y
;;; ; ; compute k
fld qword [Y]
fadd qword [one]
fmul qword [ten]
fmul qword [none]
fadd qword [twenty]
fistp qword [k]
;;; ; ; ; ; rax gets k * ncol + j
mov rax, [k]
mov rbx, [j]
imul rax, [ncol]
add rax, rbx
;;; ; ; put "*" in dl, then dl into [a2+rax]
mov dl, [star]
mov [a2+rax], dl
;;; ; ; XF = XF + DX0
fld qword [XF]
fadd qword [DX0]
fistp qword [XF]
mov rbx, [j]
inc rbx ; j++
mov [j], rbx
cmp rbx,[ncol] ; j<ncol
jne cos
;;; print
mov rax,0 ; i=0
mov [i],rax
ploopi:
mov rax,[i]
mov rbx,0 ; j=0
mov [j],rbx
ploopj:
mov rax,[i]
mov rbx,[j]
mov dl, [spc]
imul rax,[ncol]
add rax, rbx
mov rax, [i] ; a2+i*ncol+j is byte
imul rax, [ncol]
add rax, [j]
add rax, a2
mov rsi, rax ; address of character to print
mov rax, 1 ; system call 1 is write
mov rdi, 1 ; file handle 1 is stdout
mov rdx, 1 ; number of bytes
syscall ; invoke operating system to do the write
;;; print here
mov rbx,[j]
inc rbx ; j++
mov [j],rbx
cmp rbx,[ncol] ; j<ncol
jne ploopj
mov rdi, fmtend
mov rax, 1
mov rdi, 1 ; file handle 1 is stdout
mov rsi, newline ; address of string to output
mov rdx, 1 ; number of bytes
syscall
;;; print here
mov rax,[i]
inc rax ; i++
mov [i],rax
cmp rax,[nrow] ; i<ncol
jne ploopi
;;; print a2
mov eax, 60 ; system call 60 is exit
xor rdi, rdi ; exit code 0
syscall ; invoke operating system to exit
答案 0 :(得分:3)
由于[XF]
更新错误,代码无法按预期工作:
fistp qword [XF] ; will store integer.
修复XF之后,它会崩溃,因为计算的y值超出了[0,0] - &gt; [41,21]坐标。
你可以通过在绘制星星之前添加最小/最大坐标钳位来使代码更加健壮,所以如果你的计算产生错误的[x,y],它就不会将星形写入某些内存,而是其他东西(我放在那里) {= 1}}在y = 0时查看图表出错的位置。
之后你可能想要修复图表......这取决于你。
无论如何,我对你的装配技术有了更多的评论(或者我从评论中指出,你的导师的技术)。作为学生的工作,我可以容忍这种情况,但仅限于此。
要成为计算机程序员,你不应该将每一个愚蠢的翻译成计算机命令。如果人们会这样编程,在每种情况下排序仍然是完整的O(n ^ 2),没有人会创建任何压缩算法。您应该从根本上理解要实现的计算类型,并尝试尽可能简化。
让我举几个你的代码示例。最初的部分是将空格字符放在a2数组的每个位置。所以基本上它正在做:
'#'
我遇到了一个小问题......它字面意思完成了。就像每个表达式中的每个f * cking符号一样,所有内容都来回加载/存储到内存中,就像CPU上的寄存器一样不存在。
但情况更糟,我也遇到了重大问题。如果你打开你的程序员,并考虑该部分正在进行的计算,你应该弄清楚该计算的最终状态是,为for (i = 0; i < 21; ++i)
for (j = 0; j < 41; ++j)
a2[i * ncol + j] = ' ';
分配的整个内存是否填充了值a2
(32
)。并且a2在内存中占据连续的21 * 41字节。
所以要做同样的事情,你可以写下这段代码:
' '
它会用空格填充整个lea rdi,[a2] ; address of first byte of a2
lea ecx,[i-a2] ; rcx = size of a2 array in bytes
; (using label "i" after it) And only ecx as 21*41 < 2^32
mov al,' ' ; space value directly (why [spc]?)
rep stosb ; fill rcx bytes at rdi with al
。如果这些循环按列进行,则此代码将按行以不同方式填充它。但是,如果您只对计算结果感兴趣(整个数组设置为a2
),那么您不关心是否按行,列或圆圈完成。
' '
变体结束(甚至可以通过将rep stosb
填充为16或32倍的大小来进一步优化性能,然后填充它一些SSE指令或至少a2
)。
但至少在每次迭代中都认识到内循环正在进行stosd
......而你可能会这样做:
i * ncol + j
......这就像最低限度。然后,如果您要调试它,您会注意到for (i = 0; i < 21; ++i) {
rowindex = i*ncol + 0;
for (j = 0; j < 41; ++j) {
a2[rowindex] = ' ';
++rowindex;
}
}
等于前一行结束时已设置的值,因此您需要在rowindex = i*ncol + 0;
个循环之前只执行rowindex = 0;
:< / p>
for
现在您应该已经看到两个charindex = 0;
for (i = 0; i < 21; ++i)
for (j = 0; j < 41; ++j)
a2[charindex++] = ' ';
循环可以被单个for
替换...但是等一下,是不是等于for (count = 0; count < 21*41; ++count)
?噢,是的。
charindex
这相当于我的for (i = 0; i < 21*41; ++i) a2[i] = ' ';
,但如果你用简单的rep stosb
指令作为循环来写(因为你不知道mov/inc/dec/jnz
) ,我会完全没问题(它会在大致相同的时间内执行)。
但做21 * 41 rep stosb
指令就像......亵渎神明。有时间,当进行800次32位数的乘法时需要大约3-5秒。现在有人正在使用该计算能力来清除连续的字节数组。疼痛...
BTW,这是原始代码的输出(在修复imul
更新后,并且钳位值...我用点替换空格,并且钳位Y值将[XF]
转换为{{1 }}
*