Assembly 如何在集合中打印星形三角形?

Assembly 如何在集合中打印星形三角形?,assembly,nasm,x86-64,yasm,Assembly,Nasm,X86 64,Yasm,我需要获得以下输出: * ** *** **** ***** ****** ******* ******** ********* ********** 所以是10行,我的星星从1开始到10 目前我得到: ********** *********** ************ ************* ************** *************** **************** ***************** ****************** ************

我需要获得以下输出:

*
**
***
****
*****
******
*******
********
*********
**********
所以是10行,我的星星从1开始到10

目前我得到:

**********
***********
************
*************
**************
***************
****************
*****************
******************
*******************
********************
我的代码:

section.data
字符数据库''
三角形化db 0;每行星数
三角形箭头DB10;
第节.案文
全球启动
_开始
mov rax,[三角帆船];排
外环:
mov rbx,[三角形箭头]
内循环:
呼叫星
十二月十日
cmp-bx,0
jg内环
呼叫新线
召唤三角
十二月十二日
cmp ax,0
jne外环
呼叫新线
呼叫出口
出口:
mov-eax,1;系统出口
mov-ebx,0;返回0
int 80h;
ret
新行:
mov[char],字节10
推拉;
推动rbx;
mov-eax,4;系统写入
mov-ebx,1;stdout
mov-ecx,char;
mov-edx,1;新线规模
int 80h
pop-rbx;
波普雷克斯;
ret
明星:
mov[char],字节'*';
推拉;
推动rbx;
mov-eax,4;系统写入
mov-ebx,1;stdout
mov-ecx,char;
mov-edx,1;
int 80h;
pop-rbx;
波普雷克斯;
ret
下三角:
推拉;
推动rbx;
mov rax,[三角形箭头]
公司ax
mov[trianglerows],rax
流行音乐
波普雷克斯
ret
我试了又试,试了又试,但我没能得到我想要的

我似乎找不到一种方法来区分行和行的星星,因为所有这些
push
pop

老实说,我不太明白这些。我被告知需要它们来执行循环,但我不确定为什么,例如,在函数
star
中,我需要调用外部循环

我找不到任何有效的
push
pop
组合。我经常得到很多星星,或者每行一颗星星,或者只有一颗星星

我真的很困惑,我在改变什么,保持什么不变。我能够获得所需的产量,但从未停止增加

我能够得到从10颗星到1颗星的输出,但从来都不是我想要的


我做错了什么?我该如何回答这个问题?

您的第一行有10颗星,因为您在内部循环中使用了
[trianglerows]
。我确信您打算使用
[trianglesize]
(目前您在任何地方都没有使用)。然后在
down\u triangle
中,您需要再次增加
[trianglesize]
,而不是
[trianglerows]
。最后,您可能希望
[trianglesize]
以1开始,而不是以0开始,第一行为1星


此外,请务必按照Michael Petch在下面的评论中所述更正内存使用情况,否则您的变量将被损坏,因为它们共享相同的内存。

我通过这种方式解决了问题,它是32位的:

位32
全球启动
第二节数据
行dw 10
第节.案文
_开始:
movzx-ebx,字[行];ebx保存循环中使用的行数
; 在这里,我们计算有多少符号
lea eax,[ebx+3]
imul eax,ebx
shr-eax,1;shr用于除以2
; 现在eax保存所有符号的编号
mov-edx,eax;现在edx保存了打印中使用的所有符号的编号
;我们准备堆栈来填充数据
电除尘器
副esp,edx
;我们倒着填
下一行:
12月ecx
mov[ecx],字节10
mov-eax,ebx
下一颗星:
12月ecx
mov[ecx],字节'*'
dec eax
jg下一颗星
十二月下旬
jg下一条线
;印刷品;edx具有字符数;ecx是字符串上的指针
mov-eax,4;系统写入
公司;1-stdout,在循环的末尾,我们有ebx=0
int 80h;
;出口
mov-eax,1;1-系统出口
异或ebx,ebx;0-返回0
int 80h;
ret
我是怎么做到的?
首先,我计算我们要打印的符号数量。我一次把它全部打印出来。它是一个有限(算术级数)的和

在我们的情况下,我们有

我们看到3个操作
+
*
/
。我们只能通过2优化分割,进行右移:

leaeax[ebx+3];n+3
imuleax,ebx;n*(n+3)
shr-eax,1;n*(n+3)/2
我们的字符串将在堆栈上,让我们准备它以获得足够的内存:

mov-ecx,esp
副esp,edx
然后,我们用星星和
\n
s填充堆栈

下一行:
12月ecx
mov[ecx],字节10
mov-eax,ebx
下一颗星:
12月ecx
mov[ecx],字节'*'
dec eax
jg下一颗星
十二月下旬
jg下一条线
我倒着填。这是什么意思?我用符号从头到尾填充字符串。我为什么要这样做?只是因为我想尽量少用寄存器。在循环的末尾,
ecx
包含一个指针,指向要打印的字符串。如果我向前填充,
ecx
在“堆栈预分页”之前包含
esp
上的指针,并且我不能在
print
函数中将寄存器用作字符串上的指针。此外,我还必须使用另一个寄存器来递减或使用
cmp
,这比
dec

就这些,打印完毕


另一个案例

global _start

section .data
    rows dw 10

section .text
_start:

;it defines how many symbols we have to print
movzx ebx, byte[rows] ; ebx holds number of rows
lea eax,[ebx+3]
imul eax,ebx 
shr eax,1 ; now eax holds number of all symbols
mov edx,eax ; now edx holds number of all symbols, used in print

;prepare pointer
mov ecx,esp
sub ecx,eax ; ecx points on the beginning of the string, used in print

;fill the string by stars
mov eax,edx
shr eax,2
mov ebp, dword '****'
next_star:
    mov [ecx+4*eax],ebp
    dec eax
    jge next_star

;fill the string by '\n'
mov edi,esp
dec edi
mov eax,ebx; in the eax is number of rows
inc eax
next_n:
    mov [edi],byte 0xa
    sub edi,eax
    dec eax
    jg next_n

;print
;mov ecx,esp
mov eax,4;  ;sys_write
mov ebx,1;  ;1 - stdout 
int 80h;

;exit
mov eax,1       ;1 -  sys_exit
xor ebx,ebx     ;0 - return 0
int 80h;
ret
在这里,开始时我们用星号填充堆栈,然后用
\n
s填充堆栈


使用调试器查看您正在更改的位和位置。用于阅读您使用的每一条指令,并对照您在调试器中观察到的内容进行交叉检查。如果你在第一次尝试时没有完全理解一切,不要担心,继续重新阅读和检查。另外,尝试寻找更好的教程/书籍作为开始。你可以从这个开始,然后NASM/YASM在语法上有一些不同,但这在NASM文档中有介绍:顺便说一句,如果你是一个厚颜无耻的混蛋,你可以用定义为
starline:db'**************',10
(即10星和新行字符)的单个字符串输出10行三角形,输出(使用
sys_write
)从第一行的地址星线+9到最后一行的地址星线+0,第一行只有2个字符,然后是3个字符,以此类推。。。o