我有一个 x86-64 程序,仅当从 gdb 调试器运行时才能正常工作

发布于 2025-01-12 07:51:59 字数 4522 浏览 2 评论 0原文

我在 x86 汇编程序中编写了 malloc 的原始版本作为练习。该代码使用链表来跟踪分配的内存块。我决定添加一个函数来遍历列表并打印出每个块的元数据,并遇到了这个奇怪的问题。当我使用 gdb 运行代码时,它可以正常工作,但是当我不使用 gdb 直接运行时,它就不能正常工作。当我将 sbrk 返回的地址打印为十六进制字符串时,只有从 gdb 运行时才能正确打印。如果在没有 gdb 的情况下重复运行,则每次运行都会打印不同的数字。我已将代码缩减到说明问题所需的最少代码。我已经尝试了所有我能想到的方法来找出问题所在。我确信我的 itoh 和 printstring 函数工作正常。我尝试过链接 c 库并使用 put,但效果相同。我尝试将所有寄存器初始化为零。我查找了因调用 sbrk 而更改的任何寄存器,并在调用过程中保存和恢复了它们。没有任何效果。这是说明问题的代码:

global _start,itoh,printstring

section .rodata
        TRUE            equ 1
        FALSE           equ 0
        NULL            equ 0
        LF              equ 10
        sys_brk         equ 12
        exit_ok         equ 0
        sys_exit        equ 60
        sys_write       equ 1
        stdout          equ 1
        

section .data
        current_brk     dq 1
        linefeed        db LF, NULL
        msg1            db 'Test should print 0x403000 from constant: ', NULL
        msg2            db 'Test should print 0x403000 from sys_brk return: ', NULL
        number          db '--------------------', NULL

section .text

_start: mov rdi, msg1
        call printstring
        mov rdi, 0x403000
        mov rsi, number 
        mov rdx, TRUE
        call itoh
        mov rdi, number 
        call printstring

        mov rax, sys_brk
        syscall
        mov [current_brk], rax
        mov rdi, msg2
        call printstring
        mov rdi, [current_brk]
        mov rsi, number 
        mov rdx, TRUE
        call itoh
        mov rdi, number 
        call printstring

.exit:  mov rax, sys_exit
        mov rdi, exit_ok
        syscall
;
; itoh  - rdi intger to convert
;       - rsi address of string to return result
;       - rdx if true add a newline to string
;       return nothing
itoh:   push rcx
        push rax
        xor r10, r10        ; r10 counts the digits pushed onto stack
        mov r9, rdx         ; save newline flag in r9
        mov rax, rdi        ; rax is bottom half of dividend
        mov rcx, 16         ; rcx is divisor

.div:   xor rdx, rdx        ; zero rdx, top half of 128 bit dividend
        div rcx             ; divide rdx:rax by rcx
        push rdx            ; rdx is remainder
        inc r10             ; increment digit counter
        cmp rax, 0          ; is quotient zero?
        jne .div            ; no - keep dividimg by 16 and pushing remainder

.pop:   mov byte[rsi], "0"
        inc rsi
        mov byte[rsi], "x"
        inc rsi
.p0:    pop r11             ; get a digit from stack
        cmp r11, 10
        jl .p1
        sub r11, 10
        add r11, "a"
        jmp .p2
.p1:    add r11, "0"        ; convert to ascii char
.p2:    mov byte[rsi],r11b  ; copy ascii digit to string buffer
        dec r10             ; decrement digit count
        inc rsi             ; point rsi to next char position
        cmp r10, 0          ; is digit counter 0
        jne .p0             ; no, go get another digit from stack
        cmp r9, 0
        je .exit
        mov byte[rsi], LF
        inc rsi

.exit:  mov byte[rsi], NULL ; terminate string
        pop rax
        pop rcx
        ret
;
; printstring - rdi is address of string
;               return nothing
printstring:
        push rcx            ; sys_write modifies rcx
        push rax            ; sys_write modifies rax
        xor rdx, rdx        ; zero rdx, char count
        mov rsi, rdi        ; use rsi to index into string
.countloop:
        cmp byte [rsi],NULL ; end of string?
        je .countdone       ; yes, finished counting
        inc rdx             ; no, count++
        inc rsi             ; point to next char
        jmp .countloop
.countdone:
        cmp rdx, 0          ; were there any characters?
        je .printdone       ; no - exit

        mov rax, sys_write  ; write system call
        mov rsi, rdi        ; address of string
        mov rdi, stdout     ; write to stdout
        syscall             ; number of bytes to write is in rdx
.printdone:
        pop rax
        pop rcx
        ret

yasm -felf64 -gdwarf2 test.asm
ld -g -otest test.o

gdb test
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
[?2004h(gdb) run
[?2004l
Starting program: /home/david/asm/test 
Test should print 0x403000 from constant: 0x403000
Test should print 0x403000 from sys_brk return: 0x403000
[Inferior 1 (process 28325) exited normally]
[?2004h[?2004l
[?2004h(gdb) q
[?2004l

./test
Test should print 0x403000 from constant: 0x403000
Test should print 0x403000 from sys_brk return: 0x14cf000

I have written a primitive version of malloc in x86 assembler as an exercise. The code uses a linked list to keep track of allocated memory blocks. I decided to add a function to walk the list and print out the meta data for each block and encountered this weird problem. When I run the code using gdb it works properly but when run directly without gdb it does not. When I print out an address returned by sbrk as a hex string it only prints correctly if run from gdb. If run repeatedly without gdb it prints a different number each run. I have cut the code down to the minimum needed to illustrate the problem. I have tried everything I can think of to find the problem. I'm sure that my itoh and printstring funcions are working correctly. I have tried linking with the c library and using puts but it does the same. I tried initializing all registers to zero. I have looked for any registers altered by the call to sbrk and saved and restored them across the call. Nothing has worked. Here is the code that illustrates the problem:

global _start,itoh,printstring

section .rodata
        TRUE            equ 1
        FALSE           equ 0
        NULL            equ 0
        LF              equ 10
        sys_brk         equ 12
        exit_ok         equ 0
        sys_exit        equ 60
        sys_write       equ 1
        stdout          equ 1
        

section .data
        current_brk     dq 1
        linefeed        db LF, NULL
        msg1            db 'Test should print 0x403000 from constant: ', NULL
        msg2            db 'Test should print 0x403000 from sys_brk return: ', NULL
        number          db '--------------------', NULL

section .text

_start: mov rdi, msg1
        call printstring
        mov rdi, 0x403000
        mov rsi, number 
        mov rdx, TRUE
        call itoh
        mov rdi, number 
        call printstring

        mov rax, sys_brk
        syscall
        mov [current_brk], rax
        mov rdi, msg2
        call printstring
        mov rdi, [current_brk]
        mov rsi, number 
        mov rdx, TRUE
        call itoh
        mov rdi, number 
        call printstring

.exit:  mov rax, sys_exit
        mov rdi, exit_ok
        syscall
;
; itoh  - rdi intger to convert
;       - rsi address of string to return result
;       - rdx if true add a newline to string
;       return nothing
itoh:   push rcx
        push rax
        xor r10, r10        ; r10 counts the digits pushed onto stack
        mov r9, rdx         ; save newline flag in r9
        mov rax, rdi        ; rax is bottom half of dividend
        mov rcx, 16         ; rcx is divisor

.div:   xor rdx, rdx        ; zero rdx, top half of 128 bit dividend
        div rcx             ; divide rdx:rax by rcx
        push rdx            ; rdx is remainder
        inc r10             ; increment digit counter
        cmp rax, 0          ; is quotient zero?
        jne .div            ; no - keep dividimg by 16 and pushing remainder

.pop:   mov byte[rsi], "0"
        inc rsi
        mov byte[rsi], "x"
        inc rsi
.p0:    pop r11             ; get a digit from stack
        cmp r11, 10
        jl .p1
        sub r11, 10
        add r11, "a"
        jmp .p2
.p1:    add r11, "0"        ; convert to ascii char
.p2:    mov byte[rsi],r11b  ; copy ascii digit to string buffer
        dec r10             ; decrement digit count
        inc rsi             ; point rsi to next char position
        cmp r10, 0          ; is digit counter 0
        jne .p0             ; no, go get another digit from stack
        cmp r9, 0
        je .exit
        mov byte[rsi], LF
        inc rsi

.exit:  mov byte[rsi], NULL ; terminate string
        pop rax
        pop rcx
        ret
;
; printstring - rdi is address of string
;               return nothing
printstring:
        push rcx            ; sys_write modifies rcx
        push rax            ; sys_write modifies rax
        xor rdx, rdx        ; zero rdx, char count
        mov rsi, rdi        ; use rsi to index into string
.countloop:
        cmp byte [rsi],NULL ; end of string?
        je .countdone       ; yes, finished counting
        inc rdx             ; no, count++
        inc rsi             ; point to next char
        jmp .countloop
.countdone:
        cmp rdx, 0          ; were there any characters?
        je .printdone       ; no - exit

        mov rax, sys_write  ; write system call
        mov rsi, rdi        ; address of string
        mov rdi, stdout     ; write to stdout
        syscall             ; number of bytes to write is in rdx
.printdone:
        pop rax
        pop rcx
        ret

yasm -felf64 -gdwarf2 test.asm
ld -g -otest test.o

gdb test
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
[?2004h(gdb) run
[?2004l
Starting program: /home/david/asm/test 
Test should print 0x403000 from constant: 0x403000
Test should print 0x403000 from sys_brk return: 0x403000
[Inferior 1 (process 28325) exited normally]
[?2004h[?2004l
[?2004h(gdb) q
[?2004l

./test
Test should print 0x403000 from constant: 0x403000
Test should print 0x403000 from sys_brk return: 0x14cf000

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文