无法弄清楚汇编 x86 中的 printf 函数并使用操作数
Can't figure out printf function in assembly x86 and working with operands
发布这个问题我已经很紧张了,但就这样吧。我试图设计一个汇编程序来接受两个整数,然后接受一个操作数(*、+ 或 ^)。然后,根据操作数,程序将根据所选操作数执行算术序列。输出必须看起来完全像这样,假设用户输入 5,然后用户输入 6,最后用户输入 *,程序必须打印出
OP 5 * 6 = 30
现在,出于某种原因我无法理解 printf 的概念,所以我在底部的 printfunction 是我尝试打印它的荒谬方式。如果有人可以向我解释 printf 是如何工作的,我很乐意听到它!我对堆栈有非常基本的了解。另外,我没有这个指数函数,因为我不知道如何用汇编语言来做。最后,我有一个与程序无关的问题要问那些真正的计算机大神……我非常讨厌汇编语言,我在用这种语言编写基本操作时遇到了麻烦。我喜欢在 C、CPP 和 Java 中工作......这种语言是否绝对是程序员日常生存所必需的,或者这是一堂关于人们在拥有打火机之前如何生火的历史课?无论如何,欢迎回答任何问题,在此先感谢您。
;program to add, multiply, or give the power of a number
%include "asm_io.inc"
segment .data
prompt1 db "Enter a number: ", 0 ;prompts
prompt2 db "Enter another number: ", 0
prompt3 db "Enter an operand", 0
prompt4 db "OP ", 0 ;idiotic prompts for printing
prompt5 db " = ", 0 ;another printing prompt
segment .bss
num1 resd 1 ;variable for 1st number
num2 resd 1 ;variable for 2nd number
op resd 1 ;variable for operand
segment .text
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
restart:
mov eax, prompt1 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num1], eax ; store into num1
call print_nl
mov eax, prompt2 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num2], eax ; store into num2
call print_nl
mov eax, promtp3 ;print out prompt
call print_string
call print_nl
call read_char ;read operand and dispose of null
call read_char
mov [op], eax ;store operand in [op]
call print_nl
cmp [op], '*' ;operand comparison
jne jmp1
call mulFun
jmp restart
jmp1: cmp [op], '+' ;operand comparison
jne jmp2
call sumFun
jmp restart
jmp2: cmp [op], '^' ;operand comparison
jne jmp3
call expFun
jmp restart
jmp3: cmp [op], 'e' ;exit function
je end1
end1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call print_nl ; pr
popa
mov eax, 0 ; return back to C
leave
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mulfun: ;multiplication function
mov ebx, [num1]
mov ecx, [num2]
imul ebx, ecx
jmp printFun
sumFun: ;sum function
mov ebx, [num1]
mov ecx, [num2]
add ebx, ecx
call printFun
printFun: ;printing function
mov eax, [prompt4]
call print_string
mov eax, [num1]
call print_string
mov eax, [op]
call print_string
mov eax, [num2]
call print_string
mov eax, [prompt5]
call print_string
mov eax, ebx
call print_string
call print_nl
ret
我到处都发现了一个问题,我在评论中添加了 ***。需要注意的几点:
- 您的某些标签中有拼写错误
- NASM区分大小写,所以mulfun和mulFun[=61是不一样的=].
- 如果您有一条指令采用一个或多个不涉及寄存器(对于源或目标)但引用内存的操作数 - 您需要指定内存操作数的大小。例如
cmp [op], '+'
必须指定 [op] 引用的数据的大小,因此您可以在其前面加上大小。大小可以是 byte、word、dword。您正在比较单个字符,因此大小为 byte 。代码应该是这样的 cmp byte [op], '+'
- 如果你有一个变量并且你做了
mov eax, varname
这会将 varname 的地址移动到 EAX。如果你想移动 varname 的内容,你必须用方括号将它括起来,比如 mov eax, [varname]
。在处理字符串地址和 print_string 例程时,您需要在 EAX 中传递字符串的地址,而不是内容。所以省略括号。
- 如果您使用
call
调用函数,您的函数应以 ret
结尾。
- 不要
jmp
函数,使用call
- 如果你想打印一个字符不要使用print_string,使用print_char。将字符放入 EAX
- 如果你想打印一个整数,不要使用print_string,使用print_int。将整数放入 EAX
修改后的代码如下:
;program to add, multiply, or give the power of a number
%include "asm_io.inc"
segment .data
prompt1 db "Enter a number: ", 0 ;prompts
prompt2 db "Enter another number: ", 0
prompt3 db "Enter an operand", 0
prompt4 db "OP ", 0 ;idiotic prompts for printing
prompt5 db " = ", 0 ;another printing prompt
segment .bss
num1 resd 1 ;variable for 1st number
num2 resd 1 ;variable for 2nd number
op resd 1 ;variable for operand
segment .text
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
restart:
mov eax, prompt1 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num1], eax ; store into num1
call print_nl
mov eax, prompt2 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num2], eax ; store into num2
call print_nl
mov eax, prompt3 ;print out prompt
;*** Typo - promtp3 changed to prompt3
call print_string
call print_nl
call read_char ;read operand and dispose of null
call read_char
mov [op], eax ;store operand in [op]
call print_nl
cmp byte [op], '*' ;operand comparison
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
jne jmp1
call mulFun
jmp restart
jmp1: cmp byte [op], '+' ;operand comparison
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
jne jmp2
call sumFun
jmp restart
jmp2: cmp byte [op], '^' ;operand comparison
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
jne jmp3
; call expFun ;*** This expFun function doesn't exist so
;*** don't call it so we can compile and link
jmp restart
jmp3: cmp byte [op], 'e' ;exit function
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
je end1
end1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call print_nl ; pr
popa
mov eax, 0 ; return back to C
leave
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mulFun: ;multiplication function
;*** NASM is case sensitive - changed mulfun to mulFun
mov ebx, [num1]
mov ecx, [num2]
imul ebx, ecx
call printFun ;*** Call printFun, don't 'jmp' to it
ret ;*** Since mulfun was called, we use 'ret' to return
sumFun: ;sum function
mov ebx, [num1]
mov ecx, [num2]
add ebx, ecx
call printFun
ret
printFun: ;printing function
mov eax, prompt4 ;*** We want the address of prompt4, not what is at prompt4
;*** Remove the brackets from [prompt4]
call print_string
mov eax, [num1]
call print_int ;*** Use print_int to print an integer, not print_string
mov eax, [op]
call print_char ;*** Use print_char to print a char, not print_string
mov eax, [num2]
call print_int ;*** Use print_int to print an integer, not print_string
mov eax, prompt5 ;*** We want the address of prompt5, not what is at prompt5
;*** Remove the brackets from [prompt5]
call print_string
mov eax, ebx
call print_int ;*** Use print_int to print an integer, not print_string;
call print_nl
ret
expFun函数的开发就交给原作者了。暂时我已经把它注释掉了,所以现有的代码可以组装,链接,运行.
你可以使用 printf 但我认为漫长的道路也可以教一些东西,我排除了对 printf 的讨论从我的回答。您的讲师,课程 material,助教将是您开始解决其他问题的好地方。
提供此答案是为了让您的程序进入可用状态,以便您可以继续作业。在我看来,原来的问题太宽泛了。如果需要进一步的帮助,最好针对特定问题提出新问题。
发布这个问题我已经很紧张了,但就这样吧。我试图设计一个汇编程序来接受两个整数,然后接受一个操作数(*、+ 或 ^)。然后,根据操作数,程序将根据所选操作数执行算术序列。输出必须看起来完全像这样,假设用户输入 5,然后用户输入 6,最后用户输入 *,程序必须打印出
OP 5 * 6 = 30
现在,出于某种原因我无法理解 printf 的概念,所以我在底部的 printfunction 是我尝试打印它的荒谬方式。如果有人可以向我解释 printf 是如何工作的,我很乐意听到它!我对堆栈有非常基本的了解。另外,我没有这个指数函数,因为我不知道如何用汇编语言来做。最后,我有一个与程序无关的问题要问那些真正的计算机大神……我非常讨厌汇编语言,我在用这种语言编写基本操作时遇到了麻烦。我喜欢在 C、CPP 和 Java 中工作......这种语言是否绝对是程序员日常生存所必需的,或者这是一堂关于人们在拥有打火机之前如何生火的历史课?无论如何,欢迎回答任何问题,在此先感谢您。
;program to add, multiply, or give the power of a number
%include "asm_io.inc"
segment .data
prompt1 db "Enter a number: ", 0 ;prompts
prompt2 db "Enter another number: ", 0
prompt3 db "Enter an operand", 0
prompt4 db "OP ", 0 ;idiotic prompts for printing
prompt5 db " = ", 0 ;another printing prompt
segment .bss
num1 resd 1 ;variable for 1st number
num2 resd 1 ;variable for 2nd number
op resd 1 ;variable for operand
segment .text
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
restart:
mov eax, prompt1 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num1], eax ; store into num1
call print_nl
mov eax, prompt2 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num2], eax ; store into num2
call print_nl
mov eax, promtp3 ;print out prompt
call print_string
call print_nl
call read_char ;read operand and dispose of null
call read_char
mov [op], eax ;store operand in [op]
call print_nl
cmp [op], '*' ;operand comparison
jne jmp1
call mulFun
jmp restart
jmp1: cmp [op], '+' ;operand comparison
jne jmp2
call sumFun
jmp restart
jmp2: cmp [op], '^' ;operand comparison
jne jmp3
call expFun
jmp restart
jmp3: cmp [op], 'e' ;exit function
je end1
end1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call print_nl ; pr
popa
mov eax, 0 ; return back to C
leave
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mulfun: ;multiplication function
mov ebx, [num1]
mov ecx, [num2]
imul ebx, ecx
jmp printFun
sumFun: ;sum function
mov ebx, [num1]
mov ecx, [num2]
add ebx, ecx
call printFun
printFun: ;printing function
mov eax, [prompt4]
call print_string
mov eax, [num1]
call print_string
mov eax, [op]
call print_string
mov eax, [num2]
call print_string
mov eax, [prompt5]
call print_string
mov eax, ebx
call print_string
call print_nl
ret
我到处都发现了一个问题,我在评论中添加了 ***。需要注意的几点:
- 您的某些标签中有拼写错误
- NASM区分大小写,所以mulfun和mulFun[=61是不一样的=].
- 如果您有一条指令采用一个或多个不涉及寄存器(对于源或目标)但引用内存的操作数 - 您需要指定内存操作数的大小。例如
cmp [op], '+'
必须指定 [op] 引用的数据的大小,因此您可以在其前面加上大小。大小可以是 byte、word、dword。您正在比较单个字符,因此大小为 byte 。代码应该是这样的cmp byte [op], '+'
- 如果你有一个变量并且你做了
mov eax, varname
这会将 varname 的地址移动到 EAX。如果你想移动 varname 的内容,你必须用方括号将它括起来,比如mov eax, [varname]
。在处理字符串地址和 print_string 例程时,您需要在 EAX 中传递字符串的地址,而不是内容。所以省略括号。 - 如果您使用
call
调用函数,您的函数应以ret
结尾。 - 不要
jmp
函数,使用call
- 如果你想打印一个字符不要使用print_string,使用print_char。将字符放入 EAX
- 如果你想打印一个整数,不要使用print_string,使用print_int。将整数放入 EAX
修改后的代码如下:
;program to add, multiply, or give the power of a number
%include "asm_io.inc"
segment .data
prompt1 db "Enter a number: ", 0 ;prompts
prompt2 db "Enter another number: ", 0
prompt3 db "Enter an operand", 0
prompt4 db "OP ", 0 ;idiotic prompts for printing
prompt5 db " = ", 0 ;another printing prompt
segment .bss
num1 resd 1 ;variable for 1st number
num2 resd 1 ;variable for 2nd number
op resd 1 ;variable for operand
segment .text
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
restart:
mov eax, prompt1 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num1], eax ; store into num1
call print_nl
mov eax, prompt2 ; print out prompt
call print_string
call print_nl
call read_int ; read integer
mov [num2], eax ; store into num2
call print_nl
mov eax, prompt3 ;print out prompt
;*** Typo - promtp3 changed to prompt3
call print_string
call print_nl
call read_char ;read operand and dispose of null
call read_char
mov [op], eax ;store operand in [op]
call print_nl
cmp byte [op], '*' ;operand comparison
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
jne jmp1
call mulFun
jmp restart
jmp1: cmp byte [op], '+' ;operand comparison
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
jne jmp2
call sumFun
jmp restart
jmp2: cmp byte [op], '^' ;operand comparison
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
jne jmp3
; call expFun ;*** This expFun function doesn't exist so
;*** don't call it so we can compile and link
jmp restart
jmp3: cmp byte [op], 'e' ;exit function
;*** We must specify the size of data we are
;*** comparing, so we tell the assembler that
;*** with 'byte' in front of the variable
je end1
end1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call print_nl ; pr
popa
mov eax, 0 ; return back to C
leave
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mulFun: ;multiplication function
;*** NASM is case sensitive - changed mulfun to mulFun
mov ebx, [num1]
mov ecx, [num2]
imul ebx, ecx
call printFun ;*** Call printFun, don't 'jmp' to it
ret ;*** Since mulfun was called, we use 'ret' to return
sumFun: ;sum function
mov ebx, [num1]
mov ecx, [num2]
add ebx, ecx
call printFun
ret
printFun: ;printing function
mov eax, prompt4 ;*** We want the address of prompt4, not what is at prompt4
;*** Remove the brackets from [prompt4]
call print_string
mov eax, [num1]
call print_int ;*** Use print_int to print an integer, not print_string
mov eax, [op]
call print_char ;*** Use print_char to print a char, not print_string
mov eax, [num2]
call print_int ;*** Use print_int to print an integer, not print_string
mov eax, prompt5 ;*** We want the address of prompt5, not what is at prompt5
;*** Remove the brackets from [prompt5]
call print_string
mov eax, ebx
call print_int ;*** Use print_int to print an integer, not print_string;
call print_nl
ret
expFun函数的开发就交给原作者了。暂时我已经把它注释掉了,所以现有的代码可以组装,链接,运行.
你可以使用 printf 但我认为漫长的道路也可以教一些东西,我排除了对 printf 的讨论从我的回答。您的讲师,课程 material,助教将是您开始解决其他问题的好地方。
提供此答案是为了让您的程序进入可用状态,以便您可以继续作业。在我看来,原来的问题太宽泛了。如果需要进一步的帮助,最好针对特定问题提出新问题。