c-循环计数器时的NASM组件



我正在汇编中编写一个while循环,以便在Linux终端中使用nasm和gcc进行编译。程序将x和y进行比较,直到y>=x,并在结束时报告循环数。这是代码:

segment .data
out1    db "It took ", 10, 0
out2    db "iterations to complete loop. That seems like a lot.", 10, 0
x       db 10
y       db 2
count   db 0
segment .bss
segment .text
global main
extern printf
main:
mov    eax, x
mov    ebx, y
mov    ecx, count
jmp    lp         ;jump to loop lp
lp:
cmp    ebx, eax   ;compare x and y
jge    end        ;jump to end if y >= x
inc    eax        ;add 1 to x
inc    ebx        ;add 2 to y
inc    ebx
inc    ecx        ;add 1 to count
jp     lp         ;repeat loop
end:
push    out1      ;print message part 1
call    printf
push    count     ;print count
call    printf
push    out2      ;print message part 2
call    printf
;mov    edx, out1               ;
;call   print_string            ;
;
;mov    edx, ecx                ;these were other attempts to print
;call   print_int               ;using an included file
;
;mov    edx, out2               ;
;call   print_string            ;

这是在终端中编译和运行的:

nasm -f elf test.asm
gcc -o test test.o
./test

终端输出为:

It took
iterations to complete loop. That seems like a lot.
Segmentation fault (core dumped)

我看不出这个逻辑有什么错。我认为这是语法上的,但我们刚刚开始学习汇编,我尝试了各种不同的语法,比如变量周围的括号和在片段末尾使用ret,但似乎都不起作用。我也搜索过分割错误,但没有发现任何真正有用的东西。任何帮助都将不胜感激,因为我是一个绝对的初学者。

它崩溃的原因可能是main函数没有ret指令。同时确保将eax设置为0以表示成功:

xor     eax, eax ; or `mov eax, 0` if you're more comfortable with that
ret

此外,全局变量指定指针,而不是值。CCD_ 5将CCD_ 6设置为CCD_。如果你想发生任何事情(或者不使用全局变量),你需要写回它。

最后,您使用一个非字符串参数调用printf

push    count     ;print count
call    printf

第一个参数需要是一个格式字符串,如"%i"。这里,count是一个指向空字节的指针,因此您将一无所获。在我的脑海里,你应该试试这个:

out3    db "%i ", 0
; snip
push    ecx
push    out3
call    printf

我认为您的问题可能只是引用了常量的地址,而不是它们的内在值。必须将nasm中的标签视为指针而非值。要访问它,您只需要使用[label]:

segment .data
x      dw 42
segment .text
global main
extern printf
main:
mov    eax, x
push   eax
call   printf   ; will print address of x (like doing cout<<&x in C++)
mov    eax, [x]
push   eax
call   printf   ; will print 42
sub    esp, 8
xor    eax, eax
ret

附言:我想没有人提到过,但在调用外部代码(C或C++或其他)时,易失性寄存器经常被修改,因为在编译时,你使用的那些函数会被"翻译"为汇编,然后与你的asm文件链接。PC不是人,所以它不区分用高级或低级编写的内容,处理器只是读取存储在寄存器和内存中的操作码和操作数,因此,当使用低级语言(call printf)时,外部函数将修改(或不修改!总是取决于编译器和体系结构)您也在使用的寄存器。为了解决这个问题,有各种解决方案:

  1. 使用gcc your_c_file.c -S检查哪些寄存器未被修改,然后在文件your_c_file.s中将是编译器从C文件中生成的预先准备好的汇编代码。(通常很难弄清楚什么是什么,如果你要使用这种方法,请查看Name Mangling,看看函数名称将如何更改。)

  2. 将所有要保存的寄存器推入堆栈,然后在调用后将它们弹回寄存器,记住LIFO方法。

  3. 使用分别推送或弹出所有寄存器的指令PUSHAPOPA

这是NASM手册的第3章,它解释了要使用的语言的基础:http://www.csie.ntu.edu.tw/~comp03/nasm/nasmdoc3.html

希望你能解决这个问题。

最新更新