我想撰寫一個簡單的 x86 程式,它存盤 2 個陣列:一個列出學生的姓名,另一個列出他們的成績。假設我想要每個 8 個位元組,我決定簡單地在堆疊上分配兩個記憶體段: (1)grade_ptr,它指向學生的成績并保存 8 * [num_students] 個位元組;(2) names_ptr,它指向一個學生姓名陣列,也包含 8 * [num_students] 位元組。
我撰寫了以下代碼來完成此任務:
mov rdi, [num_students]
mov rbp, rsp
shl rdi, 3
sub rsp, rdi
and rsp, -16 ; Align stack by rounding rsp down to multiple of 16.
mov [names_ptr], rsp
mov rdi, [num_students]
shl rdi, 3
sub rsp, rdi
and rsp, -16
mov [grades_ptr], rsp
當我運行程式時,names_ptr溢位并開始進入 占用的空間grades_ptr,但我不確定為什么。請參閱以下輸出作為示例。
Enter number students: 3
Enter student 0's name: 1
Enter student 0's grade: 60
Enter student 1's name: 2
Enter student 1's grade: 70
Enter student 2's name: 3
Enter student 2's grade: 80
Grade is 50 (ASCII code for "2")
Grade is 51 (ASCII code for "3")
Grade is 80
如您所見,每個名稱都會覆寫上一個年級。我認為問題源于我如何在頂部代碼的堆疊上分配記憶體。有人能找出我的錯誤并指出我正確的方向嗎?
section .data
num_students_prompt db "Enter number students: ",0
int_format db "%lld",0 ; lld to read 8-byte int.
stud_name_prompt db "Enter student %d's name: ",0
stud_name_format db "s",0 ; 10-char(byte) str.
stud_grade_prompt db "Enter student %d's grade: ",0
min_grade_format db "Min grade is: %d",10,0
max_grade_format db "Max grade is: %d",10,0
avg_grade_format db "Avg grade is: %d",10,0
ptr_format db "Ptr is: %d",10,0
grade_format db "Grade is %d",10,0
sum_format db "Sum grade is: %d",10,0
section .bss
num_students resq 1
grade_sum resq 1
min_grade resq 1
max_grade resq 1
avg_grade resq 1
names_ptr resq 2
grades_ptr resq 2
section .text
global main
extern scanf, printf, malloc
main:
push rbp
mov rbp, rsp
call _prompt_num_els
xor rax, rax ; al stores number vector params to scanf, so it must be empty
mov rdi, int_format ; before a printf/scanf call.
lea rsi, [num_students]
call scanf
mov rdi, [num_students]
shl rdi, 3
sub rsp, rdi
and rsp, -16
mov [names_ptr], rax
xor eax, eax
mov rdi, ptr_format
mov rsi, [names_ptr]
call printf
mov rdi, [num_students]
mov rbp, rsp
shl rdi, 3
sub rsp, rdi
and rsp, -16 ; Solve stack alignment by rounding stack ptr down to multiple of 16.
mov [grades_ptr], rsp
xor eax, eax
mov rdi, ptr_format
mov rsi, [grades_ptr]
call printf
xor rbx, rbx
_get_student:
call _prompt_name
xor rax, rax
mov rdi, stud_name_format
lea rsi, [names_ptr rbx*8]
call scanf
call _prompt_grade
xor rax, rax
mov rdi, int_format
lea rsi, [grades_ptr rbx*8]
call scanf
inc rbx
cmp rbx, [num_students]
jl _get_student
mov rax, [grades_ptr]
mov [min_grade], rax ; Before loop, we'll set min/max equal to first grade.
mov [max_grade], rax
xor rbx, rbx
_get_stats:
mov rax, [grades_ptr rbx*8]
add [grade_sum], rax
xor eax, eax
mov rdi, grade_format
mov rsi, [grades_ptr rbx*8]
call printf
cmp [min_grade], rax
jg _grade_is_min
cmp [max_grade], rax
jl _grade_is_max
jmp _loop_logic
_grade_is_min:
mov [min_grade], rax
jmp _loop_logic
_grade_is_max:
mov [max_grade], rax
_loop_logic:
inc rbx
cmp rbx, [num_students]
jl _get_stats
xor edx, edx ; rdx contains upper 64 bits of dividend.
mov rax, [grade_sum] ; rax contains lower 64 bits.
mov rcx, [num_students]
div rcx ; Compute (rdx:rax)/[num_students].
mov [avg_grade], rax
xor edx, edx
mov rdi, sum_format
mov rsi, [grade_sum]
call printf
xor rax, rax
mov rdi, max_grade_format
mov rsi, [max_grade]
call printf
xor rax, rax
mov rdi, min_grade_format
mov rsi, [min_grade]
call printf
xor rax, rax
mov rdi, avg_grade_format
mov rsi, [avg_grade]
call printf
mov rsp, rbp
pop rbp
mov rax, 60
mov rdi, 0
syscall ; Exit w/ return code 0.
_prompt_name:
xor rax, rax
mov rdi, stud_name_prompt
mov rsi, rbx
call printf
ret
_prompt_grade:
xor rax, rax
mov rdi, stud_grade_prompt
mov rsi, rbx
call printf
ret
_prompt_num_els:
xor eax, eax
mov rdi, num_students_prompt
call printf
ret
uj5u.com熱心網友回復:
在幾個地方有這樣的代碼:
lea rsi, [names_ptr rbx*8]
或
mov rax, [grades_ptr rbx*8]
這不會像您想要的那樣通過記憶體中的指標間接進行。它所做的是相對于變數 names_ptr 的地址的索引,而不是存盤在該變數中的指標。
要解決此問題,您必須將指標加載到暫存器中,然后執行索引操作。所以你可以用以下內容替換第一個:
mov rsi, [names_ptr]
lea rsi, [rsi rbx*8]
更好的是利用可用的暫存器。將 names_ptr 放在 r14 中,將 grades_ptr 放在 r15 中。然后您lea rsi, [r14 rbx*8]每次都可以使用而無需額外負載。
確保在函式的開頭按下 r14 和 r15(以及 rbx)。這不是絕對必要的,因為您不從函式回傳,但這是一個好習慣。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/365365.html
上一篇:“ldrpc,_boot”和“b_boot”有什么區別?
下一篇:匯編程式中將輸入字串轉換為小寫
