【发布时间】:2018-04-19 09:48:08
【问题描述】:
我从 16 位 msdos 改编了一个 tictactoe,以在 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
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
但是标签 update_draw 的这一行存在分段错误:
mov [rbx], cl
我只是无法理解我做错了什么。任何建议或帮助将不胜感激
编辑: 我已经编辑了添加建议的代码,奇怪的是,我发现 change_player 标签没有改变任何东西,实际上看起来我的整个代码没有设法修改部分数据的变量。例如,
change_player:
mov si, player
xor byte[si], 1 ; Tipo um xor swap :)
ret
不改变变量 player,值始终为“0”
【问题讨论】:
-
段错误在哪条指令上?使用
gdb找出答案。这是一个几乎没有任何 cmets 的大量代码转储,与 minimal reproducible example 相反。 idownvotedbecau.se/nodebuggingidownvotedbecau.se/toomuchcodeidownvotedbecau.se/unreadablecode -
哦,代码后面有文字,我是在修复您的格式后才看到的。此时
rbx中的值是什么(使用调试器检查。mov bl, byte[game_position_pointer + rax]写入 RBX 的低字节,因此这看起来很可疑,除非在到达使用它作为指针的指令之前将 RBX 设置为有效指针,或者,如果您要索引 256 字节对齐的内容,并且部分寄存器写入是进行数组索引的一种 hacky 方式。 -
mov si, [player]是替换si中先前值的负载。您的意思是用mov [player], si存储吗? x86-64 有很多寄存器;您可能根本不需要内存,例如xor r15d, 1。下次遇到困难时,使用调试器单步检查寄存器。 -
其实我忘了编辑这最后一部分,现在看看。
-
xor 正在正常工作,我在这些变量中写入的任何内容实际上都没有被写入。再比如update_draw标签,mov [rbx], cl这行好像没什么效果。
标签: assembly segmentation-fault x86-64 tic-tac-toe