Assembly 程序集x64 linux TictaToe上的分段故障
我对16位MSDO的TictaToe进行了改编,以在64位linux上工作Assembly 程序集x64 linux TictaToe上的分段故障,assembly,segmentation-fault,x86-64,tic-tac-toe,Assembly,Segmentation Fault,X86 64,Tic Tac Toe,我对16位MSDO的TictaToe进行了改编,以在64位linux上工作 section .bss game_position_pointer resb 9 key resb 1 section .data new_line db 10 nl_size equ $-new_line game_draw db "_|_|_", 10 db "_|_|_", 10 db "_|_|_", 10, 0 gd_size equ $-game_draw w
section .bss
game_position_pointer resb 9
key resb 1
section .data
new_line db 10
nl_size equ $-new_line
game_draw db "_|_|_", 10
db "_|_|_", 10
db "_|_|_", 10, 0
gd_size equ $-game_draw
win_flag db 0
player db "0", 0
p_size equ $-player
game_over_message db "FIM DE JOGO AMIGOS", 10, 0
gom_size equ $-game_over_message
game_start_message db "JOGO DA VELHA"
gsm_size equ $-game_start_message
player_message db "JOGADOR ", 0
pm_size equ $-player_message
win_message db " GANHOU!", 0
wm_size equ $-win_message
type_message db "ENTRE COM UMA POSICAO NO TABULEIRO: ", 0
tm_size equ $-type_message
clear_screen_ASCII_escape db 27,"[H",27,"[2J" ; <ESC> [H <ESC> [2J
cs_size equ $-clear_screen_ASCII_escape
section .text
global _start
_start:
call set_game_pos_pointer
main_loop:
call clear_screen
mov rsi, game_start_message
mov rdx, gsm_size
call print
mov rsi, new_line
mov rdx, nl_size
call print
mov rsi, player_message
mov rdx, pm_size
call print
mov rsi, player
mov rdx, p_size
call print
mov rsi, new_line
mov rdx, nl_size
call print
mov rsi, game_draw
mov rdx, gd_size
call print
mov rsi, new_line
mov rdx, nl_size
call print
mov rsi, type_message
mov rdx, tm_size
call print
call read_keyboard ; Vamos ler a posição que o usuário vai passar
mov al, [key]
sub al, 49 ; 49 equivale a "1" em ASCII, eu faço essa subtração porque eu quero converter ASCII para inteiro, ao mesmo tempo que faço subtraio de 1 o valor inteiro
call update_draw
call check
cmp byte[win_flag], 1
je game_over
call change_player
jmp main_loop
change_player:
mov rsi, player
xor byte[rsi], 1 ; Tipo um xor swap :)
ret
print:
mov rax, 1
mov rdi, 1
syscall
ret
read_keyboard:
mov rax, 0
mov rdi, 0
mov rsi, key
mov rdx, 1
syscall
ret
clear_screen:
mov rsi, clear_screen_ASCII_escape
mov rdx, cs_size
call print
ret
set_game_pos_pointer:
mov rsi, game_draw
mov rbx, game_position_pointer
mov rcx, 9
loop_1:
mov [rbx], rsi
add rsi, 2
inc rbx
loop loop_1
ret
update_draw:
lea rbx, [game_position_pointer + rax]
mov rsi, player
cmp byte[rsi], "0"
je draw_x
cmp byte[rsi], "1"
je draw_o
draw_x:
mov cl, "x"
jmp update
draw_o:
mov cl, "o"
jmp update
update:
mov [rbx], cl
ret
check:
call check_line
ret
check_line:
mov rcx, 0
check_line_loop:
cmp rcx, 0
je first_line
cmp rcx, 1
je second_line
cmp rcx, 2
je third_line
call check_column
ret
first_line:
mov rsi, 0
jmp do_check_line
second_line:
mov rsi, 3
jmp do_check_line
third_line:
mov rsi, 6
jmp do_check_line
do_check_line:
inc rcx
lea rbx, [game_position_pointer + rsi]
mov al, [rbx]
cmp al, "_"
je check_line_loop
inc rsi
lea rbx, [game_position_pointer + rsi]
cmp al, [rbx]
jne check_line_loop
inc rsi
lea rbx, [game_position_pointer + rsi]
cmp al, [rbx]
jne check_line_loop
mov byte[win_flag], 1
ret
check_column:
mov rcx, 0
check_colum_loop:
cmp rcx, 0
je first_column
cmp rcx, 1
je second_column
cmp rcx, 2
je third_column
call check_diagonal
ret
first_column:
mov rsi, 0
jmp do_check_column
second_column:
mov rsi, 1
jmp do_check_column
third_column:
mov rsi, 2
jmp do_check_column
do_check_column:
inc rcx
lea rbx, [game_position_pointer + rsi]
mov al, [rbx]
cmp al, "_"
je check_colum_loop
add rsi, 3
lea rbx, [game_position_pointer + rsi]
cmp al, [rbx]
jne check_colum_loop
add rsi, 3
lea rbx, [game_position_pointer + rsi]
cmp al, [rbx]
jne check_colum_loop
mov byte[win_flag], 1
ret
check_diagonal:
mov rcx, 0
check_diagonal_loop:
cmp rcx, 0
je first_diagonal
cmp rcx, 1
je second_diagonal
ret
first_diagonal:
mov rsi, 0
mov rdx, 4 ; tamanho do pulo que vamos dar para o meio da diagonal
jmp do_check_diagonal
second_diagonal:
mov rsi, 2
mov rdx, 2
jmp do_check_diagonal
do_check_diagonal:
inc rcx
lea rbx, [game_position_pointer + rsi]
mov al, [rbx]
cmp al, "_"
je check_diagonal_loop
add rsi, rdx
lea rbx, [game_position_pointer + rsi]
cmp al, [rbx]
jne check_diagonal_loop
add rsi, rdx
lea rbx, [game_position_pointer + rsi]
cmp al, [rbx]
jne check_diagonal_loop
mov byte[win_flag], 1
ret
game_over:
call clear_screen
mov rsi, game_start_message
mov rdx, gsm_size
call print
mov rsi, new_line
mov rdx, nl_size
call print
mov rsi, game_draw
mov rdx, gd_size
call print
mov rsi, new_line
mov rdx, nl_size
call print
mov rsi, game_over_message
mov rdx, gom_size
call print
mov rsi, player_message
mov rdx, pm_size
call print
mov rsi, player
mov rdx, p_size
call print
mov rsi, win_message
mov rdx, wm_size
call print
jmp fim
fim:
mov rax, 60
mov rdi, 0
syscall
我只是不明白我做错了什么。如有任何建议或帮助,将不胜感激
编辑:
我编辑了添加建议的代码,奇怪的是,我发现change\u player标签没有改变任何东西,事实上,我的整个代码似乎没有修改节数据的变量。比如说,
change_player:
mov si, player
xor byte[si], 1 ; Tipo um xor swap :)
ret
如果不更改变量player,则值始终为“0”一些位看起来可疑,尤其是
mov bl, byte[game_position_pointer + rax]
及
bl覆盖rbx的最低8位,因此操作看起来像是将字节从“rax”中的板位置移动到bl中。rbx随后用作指针(即,您的故障指令)
在第二个示例中,其目的似乎是将线路板位置的地址加载到rbx中,然后获取该位置的值。那看起来像
lea rbx, [game_position_pointer + rsi]
mov al, [rbx]
还是更简洁
mov al, game_position_pointer[rsi]
抱歉,如果我把语法弄错了,我不熟悉你的汇编语言风格。GNU提供了更精确的语法。在:
mov rbx, [game_position_pointer + rsi]
mov al,[rbx]
您使用位置[game\u position\u pointer+rsi]
中的值作为导致分段错误的指针,您需要使用game\u position\u pointer+rsi
位置本身
**我不知道它是否适用于你的游戏,或者你可以直接使用它
mov al ,byte[game_position_pointer + rsi]
segfault在哪个指令上?使用
gdb
查找。这是一个几乎没有任何注释的大规模代码转储,与。哦,代码后面有文本,我只是在修改了你的格式后才看到的。此时,rbx
中的值是多少(使用调试器检查。mov bl,byte[game\u position\u pointer+rax]
写入RBX的低位字节,因此看起来很可疑,除非在到达使用RBX作为指针的指令之前,有其他东西将其设置为有效指针,或者如果您正在索引到256字节对齐的内容,并且部分寄存器写入是一种进行数组索引的黑客方法。mov si,[player]
是一个加载,它替换了si
中以前的值。您是想用mov[player]存储吗,si
?x86-64有很多寄存器;您可能根本不需要内存,例如,xor r15d,1
。使用调试器单步执行,下次遇到问题时检查寄存器。实际上我忘了编辑最后一部分,现在看看它。xor正在按它应该的方式工作,我在这些变量中编写的任何内容实际上都没有被修改另一个例子是更新画图标签,线条mov[rbx],cl似乎没有任何效果。我编辑了代码并做了一些修改,比如lea rbx[game_position_pointer+rsi]Thx作为回复!数组game_position_pointer的内容是9个地址,这就是为什么我使用位置[game_position_pointer+rsi]中的值作为指针。但导致seg f。我不知道如何取消对地址的引用。再说一次,masm语法很混乱,但您似乎将player用作指针而不是标签。我很惊讶您没有得到太多SEGV。当我说“混乱”时,gas的“粗糙”语法的好处是,您明确区分了加载地址和值;而DOS asm掩盖了这一点。我在这里测试,发现sys\u read在我键入位置后读取“\n”,因此它跳过下一个循环并返回“0”,使得impression player变量从未改变。哈哈。尽管如此,问题仍然存在,在game_position_指针中,函数集_game_position_指针应该将棋盘的每个正方形与位置关联,当调用update_draw时,指针工作正常,但字符串game_draw不受影响。
mov rbx, [game_position_pointer + rsi]
mov al,[rbx]
mov al ,byte[game_position_pointer + rsi]