使用 NASM x86 程序集绘制余弦波
ploting a cosine wave using NASM x86 assembly
我必须使用汇编语言绘制一个简单的余弦 (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
代码未按预期运行,因为 [XF]
更新错误:
fistp qword [XF] ; will store integer.
修复 XF 后,它会崩溃,因为计算出的 y 值超出了 [0,0] -> [41,21] 坐标。
您可以通过在绘制星星之前添加 min/max 坐标钳位来使您的代码更健壮,因此如果您的计算产生错误的 [x,y],它不会将星星写入某些内存,而是写入其他内容(我把 '#'
放在 y=0 处,看看你的图表哪里出了问题)。
之后您可能会想要修复图表...这取决于您。
无论如何,我对您的组装技术有更多的评论(或者正如我从评论中注意到的,您的导师的技术)。作为学生的作品,我可以容忍,但仅此而已。
要成为计算机程序员,您不应该只是将每一个愚蠢的字面意思翻译成计算机命令。如果人们这样编程,排序在任何情况下都仍然是完整的 O(n^2),并且没有人会创建任何压缩算法。你应该从根本上理解你想要实现什么样的计算,并尽可能简化。
让我从你的代码中给你举个例子。初始部分是将 space 字符放入 a2 数组的每个位置。所以基本上它在做:
for (i = 0; i < 21; ++i)
for (j = 0; j < 41; ++j)
a2[i * ncol + j] = ' ';
我有一个小问题..它是按字面意思完成的。就像每个表达式中的每个 f*cking 符号一样,所有内容都来回 loaded/stored 到内存中,就像 CPU 上的寄存器不存在一样。
但更糟糕的是,我也遇到了很大的问题。如果你戴上程序员的帽子,想想那部分正在进行什么计算,你应该弄清楚该计算的最终状态是,分配给 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
它将用 space 填充整个 a2
。如果这些循环按列进行,那么这段代码将以不同的方式按行进行填充。但是如果你只对计算结果感兴趣(整个数组设置为 ' '
),那么你不关心它是按行、列还是圆来完成的。
等等...该代码中还有一些更奇怪的东西,但我不愿意根据自己的喜好重写它,我希望这足以说明我的想法。
顺便说一句,我不希望学生立即以 rep stosb
变体结束(甚至可以通过将 a2
填充为 16 或 32 乘法大小来进一步优化性能,并且填写一些 SSE 说明或至少 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;
等于上一行结束时已经设置的值,所以你只需要在两个 for
循环之前做 rowindex = 0;
:
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
指令编写它作为循环(因为你不知道 rep stosb
),我会完全没问题(它会在大致相同的时间执行)。
但是执行 21*41 imul
指令就像是……亵渎。曾经有一段时间,对 32 位数字进行 800 次乘法运算大约需要 3-5 秒。现在有人正在使用这种计算能力来清除连续的字节数组。痛...
顺便说一句,这是您原始代码的输出(在修复 [XF]
更新和钳位值之后......我用点替换了 spaces,并且钳位 Y 值变成 *
变成 #
.
.......................*#################
.........................................
.........................................
.........................................
.........................................
*.....................*..................
.*.......................................
..*......................................
.........................................
...*.................*...................
.........................................
....*....................................
.....*..............*....................
.........................................
......*............*.....................
.......*.................................
........*.........*......................
.........*.......*.......................
..........*..............................
...........*...**........................
............***..........................
我必须使用汇编语言绘制一个简单的余弦 (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
代码未按预期运行,因为 [XF]
更新错误:
fistp qword [XF] ; will store integer.
修复 XF 后,它会崩溃,因为计算出的 y 值超出了 [0,0] -> [41,21] 坐标。
您可以通过在绘制星星之前添加 min/max 坐标钳位来使您的代码更健壮,因此如果您的计算产生错误的 [x,y],它不会将星星写入某些内存,而是写入其他内容(我把 '#'
放在 y=0 处,看看你的图表哪里出了问题)。
之后您可能会想要修复图表...这取决于您。
无论如何,我对您的组装技术有更多的评论(或者正如我从评论中注意到的,您的导师的技术)。作为学生的作品,我可以容忍,但仅此而已。
要成为计算机程序员,您不应该只是将每一个愚蠢的字面意思翻译成计算机命令。如果人们这样编程,排序在任何情况下都仍然是完整的 O(n^2),并且没有人会创建任何压缩算法。你应该从根本上理解你想要实现什么样的计算,并尽可能简化。
让我从你的代码中给你举个例子。初始部分是将 space 字符放入 a2 数组的每个位置。所以基本上它在做:
for (i = 0; i < 21; ++i)
for (j = 0; j < 41; ++j)
a2[i * ncol + j] = ' ';
我有一个小问题..它是按字面意思完成的。就像每个表达式中的每个 f*cking 符号一样,所有内容都来回 loaded/stored 到内存中,就像 CPU 上的寄存器不存在一样。
但更糟糕的是,我也遇到了很大的问题。如果你戴上程序员的帽子,想想那部分正在进行什么计算,你应该弄清楚该计算的最终状态是,分配给 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
它将用 space 填充整个 a2
。如果这些循环按列进行,那么这段代码将以不同的方式按行进行填充。但是如果你只对计算结果感兴趣(整个数组设置为 ' '
),那么你不关心它是按行、列还是圆来完成的。
等等...该代码中还有一些更奇怪的东西,但我不愿意根据自己的喜好重写它,我希望这足以说明我的想法。
顺便说一句,我不希望学生立即以 rep stosb
变体结束(甚至可以通过将 a2
填充为 16 或 32 乘法大小来进一步优化性能,并且填写一些 SSE 说明或至少 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;
等于上一行结束时已经设置的值,所以你只需要在两个 for
循环之前做 rowindex = 0;
:
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
指令编写它作为循环(因为你不知道 rep stosb
),我会完全没问题(它会在大致相同的时间执行)。
但是执行 21*41 imul
指令就像是……亵渎。曾经有一段时间,对 32 位数字进行 800 次乘法运算大约需要 3-5 秒。现在有人正在使用这种计算能力来清除连续的字节数组。痛...
顺便说一句,这是您原始代码的输出(在修复 [XF]
更新和钳位值之后......我用点替换了 spaces,并且钳位 Y 值变成 *
变成 #
.
.......................*#################
.........................................
.........................................
.........................................
.........................................
*.....................*..................
.*.......................................
..*......................................
.........................................
...*.................*...................
.........................................
....*....................................
.....*..............*....................
.........................................
......*............*.....................
.......*.................................
........*.........*......................
.........*.......*.......................
..........*..............................
...........*...**........................
............***..........................