You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GAS(AT&T)汇编中修改某地址值后另一地址值异常变化的原因

汇编函数ints_to_ascii数据篡改问题分析

问题描述

  • 函数功能:接收一组(x,y)坐标数组(每个数是0-32767范围内的无符号整数),转换为ASCII格式"x \t y \n"并存入目标缓冲区,从坐标数组末尾反向处理至起始,仅处理最后一组数据时出现异常。
  • 测试输入(十进制):2084, 3146, 30093, 9127
  • 异常现象:加载4个16位无符号整数后,通过GDB确认%rdi指向的第一个数初始值为2084;但执行movb $10, (%rcx) # insert newline语句后,%rdi指向的地址值发生了意外篡改,已通过多次插入movq (%rdi), %r12 # test to see what is stored at (%rdi)定位到该语句为数据变化的触发点。

函数代码

.section .text
.globl ints_to_ascii # void ints_to_ascii()
#   %rdi = Array start address 
#   %rsi = Data length
#   %rdx = print buffer address
#   %rcx = print buffer length

ints_to_ascii:

    push %rbp
    movq %rsp, %rbp

    addq %rdi, %rsi     # make rsi point at end of coordinate array, used to get 8 byte numbers

    addq %rdx, %rcx     # make rcx point at end of buffer
    movq $10, %r10      # Divisor (10 for decimal)

    
.LparseData_coordinateLoop:
    
    cmpq %rdi, %rsi 
    jle .LparseData_coordinateLoop_end
    
    dec %rcx           # Move the pointer one position to the left
    movq (%rdi), %r12   # test to see what is stored at (%rdi)
    movb $10, (%rcx)    # insert newline

    movq (%rdi), %r12   # test to see what is stored at (%rdi)
    subq $8, %rsi      # point to the next place for a number
    movq (%rsi), %rax
    
convert_y_loop:

    xorq %rdx, %rdx        # Clear the remainder
    divq %r10              # Divide RAX by 10, result in RAX, remainder in RDX
    
    dec %rcx           # Move the pointer one position to the left
    mov %dl, (%rcx)  # Store the ASCII digit in the buffer
    addq $48, (%rcx)    #add 48 to convert to ascii

    cmpq $0, %rax       # Check if quotient is zero
    jne convert_y_loop       # If not zero, continue the loop

convert_y_loop_end:

    dec %rcx           # Move the pointer one position to the left
    movb $9, (%rcx)     # insert tab

    subq $8, %rsi      # point to the next place for a number
    movq (%rsi), %rax

convert_x_loop:
    xorq %rdx, %rdx        # Clear the remainder
    divq %r10              # Divide RAX by 10, result in RAX, remainder in RDX

    dec %rcx           # Move the pointer one position to the left
    mov %dl, (%rcx)       # Store the ASCII character
    addq $48, (%rcx)    #add 48 to convert to ascii

    cmpq $0, %rax       # Check if quotient is zero
    jne convert_x_loop       # If not zero, continue the loop

convert_x_loop_end:

    jmp .LparseData_coordinateLoop
.LparseData_coordinateLoop_end:

    movq %rbp, %rsp
    pop %rbp
    ret

问题根源

  1. 缓冲区越界写入:函数中%rcx初始指向缓冲区末尾,每次通过dec %rcx往回写入字符,但未做边界检查。当处理最后一组坐标时,%rcx会越过缓冲区起始地址%rdx,写到输入数组的内存区域(即%rdi指向的地址),导致movb $10, (%rcx)直接篡改了输入数组的数据。
  2. 数据步长与内存布局错误:输入的每个坐标是16位(2字节)无符号整数,但函数中错误地按8字节(64位)处理(subq $8, %rsi),同时初始计算数组末尾的逻辑addq %rdi, %rsi完全错误——%rsi是元素个数,正确的数组末尾地址应为%rdi + (%rsi * 2),原逻辑直接将元素个数加到起始地址上,导致指针定位完全混乱,进一步加剧了越界问题。

修复建议

  • 修正内存指针计算:
    • 数组末尾地址计算:将addq %rdi, %rsi改为lea (%rdi, %rsi, 2), %rsi(每个元素2字节,元素个数为%rsi)。
    • 指针移动步长:将两处subq $8, %rsi改为subq $2, %rsi,匹配16位整数的内存宽度。
  • 增加缓冲区边界检查:每次dec %rcx后,添加cmpq %rdx, %rcx,若jl(小于起始地址)则终止处理,避免越界写。
  • 调整循环终止条件:原循环cmpq %rdi, %rsi需结合修正后的步长,确保循环处理完所有(x,y)组。

内容的提问来源于stack exchange,提问作者Gusbc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:30:25