我试图输入我的程序......所有这一切都是通过并打印出来的' 0'到屏幕。我很确定PRINTDECI功能是有效的,我之前做过它并且它有效。我只需要循环输入代码,只有在输入某个值时才退出吗?我不确定如何做到这一点......除非它的ACSII价值可能很糟糕......不管怎样,这里是我的代码(Yasm(nasm clone),Intel Syntax) :
GLOBAL _start
SECTION .text
PRINTDECI:
LEA R9,[NUMBER + 18] ; last character of buffer
MOV R10,R9 ; copy the last character address
MOV RBX,10 ; base10 divisor
DIV_BY_10:
XOR RDX,RDX ; zero rdx for div
DIV RBX ; rax:rdx = rax / rbx
ADD RDX,0x30 ; convert binary digit to ascii
TEST RAX,RAX ; if rax == 0 exit DIV_BY_10
JZ CHECK_BUFFER
MOV byte [R9],DL ; save remainder
SUB R9,1 ; decrement the buffer address
JMP DIV_BY_10
CHECK_BUFFER:
MOV byte [R9],DL
SUB R9,1
CMP R9,R10 ; if the buffer has data print it
JNE PRINT_BUFFER
MOV byte [R9],'0' ; place the default zero into the empty buffer
SUB R9,1
PRINT_BUFFER:
ADD R9,1 ; address of last digit saved to buffer
SUB R10,R9 ; end address minus start address
ADD R10,1 ; R10 = length of number
MOV RAX,1 ; NR_write
MOV RDI,1 ; stdout
MOV RSI,R9 ; number buffer address
MOV RDX,R10 ; string length
SYSCALL
RET
_start:
MOV RCX, SCORE ;Input into Score
MOV RDX, SCORELEN
MOV RAX, 3
MOV RBX, 0
SYSCALL
MOV RAX, [SCORE]
PUSH RAX ;Print Score
CALL PRINTDECI
POP RAX
MOV RAX,60 ;Kill the Code
MOV RDI,0
SYSCALL
SECTION .bss
SCORE: RESQ 1
SCORELEN EQU $-SCORE
感谢您的帮助! - 凯尔
作为旁注,根据DDD,RCX中的指针变成了一个非常大的数字...所以我想我必须让它暂停并等待我输入,但我不知道怎么做......
答案 0 :(得分:1)
'设置'在x86_64系统上调用syscall 0
(READ)是:
@xenon:~$ syscalls_lookup read
read:
rax = 0 (0x0)
rdi = unsigned int fd
rsi = char *buf
rdx = size_t count
因此,您的_start
代码应该类似于:
_start:
mov rax, 0 ; READ
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
x86_64的寄存器约定和系统调用次数完全与i386不同。
您似乎遇到的一些概念性问题:
READ不会对您键入的内容做任何解释,您似乎期望它允许您键入数字(例如,57)并让它返回值57.不。它将返回' 5'' 7','输入','垃圾' ...你的SCORELEN可能是8( resq 1)的长度,所以你读取最多8个字节。或者角色,如果你想给他们打电话。除非您键入EOF字符(^ D),否则在READ调用返回到您的代码之前,您需要键入这8个字符。
您必须将收到的字符转换为值...您可以通过简单的方式进行操作并与C库中的ATOI()链接,或者编写自己的解析器通过加法和乘法将字符转换为值(它并不难,请参阅下面的代码)。
以下用作参考:
@xenon:~$ syscalls_lookup write
write:
rax = 1 (0x1)
rdi = unsigned int fd
rsi = const char *buf
rdx = size_t count
呃......这么多......我只是重写一下:
global _start
section .text
PRINTDECI:
; input is in RAX
lea r9, [NUMBER + NUMBERLEN - 1 ] ; + space for \n
mov r10, r9 ; save end position for later
mov [r9], '\n' ; store \n at end
dec r9
mov rbx, 10 ; base10 divisor
DIV_BY_10:
xor rdx, rdx ; zero rdx for div
div rbx : rax = rdx:rax / rbx, rdx = remainder
or dl, 0x30 ; make REMAINDER a digit
mov [r9], dl
dec r9
or rax, rax
jnz DIV_BY_10
PRINT_BUFFER:
sub r10, r9 ; get length (r10 - r9)
inc r9 ; make r9 point to initial character
mov rax, 1 ; WRITE (1)
mov rdi, 1 ; stdout
mov rsi, r9 ; first character in buffer
mov rdx, r10 ; length
syscall
ret
MAKEVALUE:
; RAX points to buffer
mov r9, rax ; save pointer
xor rcx, rcx ; zero value storage
MAKELOOP:
mov al, [r9] ; get a character
or al, al ; set flags
jz MAKEDONE ; zero byte? we're done!
and rax, 0x0f ; strip off high nybble and zero rest of RAX (we're lazy!)
add rcx, rcx ; value = value * 2
mov rdx, rcx ; save it
add rcx, rcx ; value = value * 4
add rcx, rcx ; value = value * 8
add rcx, rdx ; value = value * 8 + value * 2 (== value * 10)
add rcx, rax ; add new digit
jmp MAKELOOP ; do it again
MAKEDONE:
mov rax, rcx ; put value in RAX to return
ret
_start:
mov rax, 0 ; READ (0)
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
; RAX contains HOW MANY CHARS we read!
; -OR-, -1 to indicate error, really
; should check for that, but that's for
; you to do later... right? (if RAX==-1,
; you'll get a segfault, just so you know!)
add rax, SCORE ; get position of last byte
movb [rax], 0 ; force a terminator at end
mov rax, SCORE ; point to beginning of buffer
call MAKEVALUE ; convert from ASCII to a value
; RAX now should have the VALUE of the string of characters
; we input above. (well, hopefully, right?)
mov [VALUE], rax ; store it, because we can!
; it's stored... pretend it's later... we need value of VALUE!
mov rax, [VALUE] ; get the VALUE
call PRINTDECI ; convert and display value
; all done!
mov rax, 60 ; EXIT (60/0x3C)
mov rdi, 0 ; exit code = 0
syscall
section .bss
SCORE: resb 11 ; 10 chars + zero terminator
SCORELEN equ $-SCORE
NUMBER: resb 19 ; 18 chars + CR terminator
NUMBERLEN equ $-NUMBER
我要说这个应该第一次工作,它对我来说是袖手旁观,还没有经过测试,但它应该是好。我们读取最多10个字符,用零结束它,转换为值,然后转换为ascii并将其写出来。
更合适的是,你应该将寄存器保存到每个子程序的堆栈中,好吧,某些子程序,真的,只有当你要与图书馆接口时...你自己做事让你拥有所有的你想要使用寄存器自由,你只需要记住你放在哪里!
是的,有人会说"为什么你只是乘以10而不是奇怪的添加?" ...呃...因为它在寄存器上更容易,我不必在rdx:rax中设置它。此外,它具有可读性和易懂性,特别是对于评论。随它滚!这不是一场比赛,而是学习!
机器代码很有趣!虽然没有来自编译器的帮助,但还是要把你脑子里的所有鸡蛋都玩弄了!
从技术上讲,你应该检查系统调用的返回结果(RAX)是否为READ和WRITE,适当地处理错误,yadda yadda yadda ....学习使用你的调试器(gdb或其他)。
希望这有帮助。