【问题标题】:arm assembly junk only on strings of length 12仅在长度为 12 的琴弦上的臂组件垃圾
【发布时间】:2026-02-20 14:30:02
【问题描述】:

我在树莓派上用 arm 程序集编写链表时遇到了一个奇怪的问题。我的链表适用于除长度为 12 的字符串之外的所有字符串。它在所有长度为 12 的字符串的末尾显示一个垃圾字符,我不知道为什么

感谢任何帮助

这是我正在使用的输入函数,它将地址输出到 R0 中的 malloc'd 字符串,并且似乎对于长度不为 12 的所有字符串都可以正常工作:

.equ    BUFSIZE2,256

.data
inputbuf2:  .ds BUFSIZE2
prompt:     .asciz  "Enter: "
p1:     .word   0

input:
    push {R1,R2,R5,R14}
    mov R0,#0
    bl  v_ascz        @ prints string in R1
    ldr R1,=inputbuf2
    mov R2,#BUFSIZE2
    bl  c_ascz        @ does service call for input, returns in R1
    bl  v_ascz
    bl  v_nl
    bl  strlen        @ returns string length of R1 into R0
    sub R0,#1
    mov R5,R0
    bl  alloc
    bl  store
    ldr R0,=p1
    ldr R0,[R0]
    pop {R1,R2,R5,R14}
    bx  LR

alloc:
    push {R0-R4,R14}
    bl  malloc
    ldr R1,=p1
    str R0,[R1]
    pop {R0-R4,R14}
    bx  LR

store:
    push    {R1-R4,R14}
    mov R2,#0       @ index
    ldr R4,=p1
    ldr R4,[R4]
    loop:   ldrb    R3,[R1],#1
    strb    R3,[R4],#1
    add R2,#1
    cmp R2,R5
    blt loop

    mov R3,#0
    strb    R3,[R4]       @ store null at end of string
    pop {R1-R4,R14}
    bx  LR


.end

这是我正在使用的链表添加节点功能。它分配 8 个字节,并将地址存储到前 4 个数据中,并将地址存储到后 4 个中的下一个节点:

.global list_add
@   R1  =   addr of head
@   R2  =   addr of tail
@   R3  =   data
.data
node:   .word   0

list_add:
    push    {R1-R4,R14}
    bl  alloc
    push    {R2}
    ldr R2,[R2]
    cmp R2,#0
    pop {R2}
    beq first_node
            @ normal add
    ldr R4,=node
    ldr R4,[R4]
    push    {R2}
    ldr R2,[R2]     @ R2 = tail node
    str R4,[R2,#4]  @ R2 next ptr = node
    pop {R2}
    str R4,[R2]     @ tail = node
    str R3,[R4]     @ node data = first addr of data
    mov R3,#0
    str R3,[R4,#4]
    pop {R1-R4,R14}
    bx  LR

first_node:
    push    {R1-R4}
    ldr R4,=node
    ldr R4,[R4]
    str R4,[R1]     @ head = node
    str R4,[R2]     @ tail = node
    str R3,[R4]     @ node data = data
    mov R3,#0
    str R3,[R4,#4]
    pop {R1-R4}
    pop {R1-R4,R14}
    bx  LR

alloc:
    push    {R1-R3,R14}
    mov R0,#8
    bl  malloc
    ldr R1,=node
    str R0,[R1]
    ldr R1,[R1]
    mov R3,#0
    str R3,[R1]
    str R3,[R1,#4]
    pop {R1-R3,R14}
    bx  LR

添加一堆以我女朋友的狗为中心的随机字符串,这是output。忽略数字,它们是 malloc 内存的十进制地址

【问题讨论】:

  • 使用调试器,检查内存内容与您假设的不匹配的位置,从那里找出假设和代码拆分的位置 - 这可能是您的错误。仅从输出来看,您的字符串似乎没有正确终止。
  • 谢谢,我会继续努力的!字符串是空终止的,它实际上只发生在长度为 12 的字符串上,我已经测试了很多不同的大小,所以这真的让我感到难过!不过我会继续挖掘

标签: assembly raspberry-pi arm


【解决方案1】:

按照惯例,字符串以称为“终止字符”的零字节终止。

当您调用strlen 时,您将获得字符串中的字符数,不包括标记其结束的终止字符。这会导致两个问题:

  • 当您循环复制字符串时,您不会复制终止字符。因此,您的字符串将在内存中恰好为零的下一个字节处结束,该字节可能在任何地方。您会看到未定义行为的结果:没有理由为什么 12 个字符不应该工作而其他数字可以工作,这只是您的具体情况的结果。
  • 如果您要添加终止字符,则会溢出目标字符串缓冲区,因为您对 malloc 的调用也没有为终止字符分配足够的空间。

当我在这里时,我不妨也向您推荐 ARM ABI,特别是 the part about the procedure call standard。虽然 ABI 不排除将 r0-r3 用于中间值,但这些寄存器(连同 r12)是“呼叫破坏”,因此通常使用 r4-r11 进行中间计算。函数必须保留r4-r11,通常使用堆栈。因此,您使用r5 来保存函数参数(对store)与ABI 相悖,因此您的store 函数将无法从符合ABI 的代码中调用;如果您的呼叫者也符合 ABI,那么您在多个地方推送/弹出r1-r3 是不必要的。另外值得注意的是,ABI 需要在不同翻译单元中的函数调用之间进行 8 字节堆栈对齐,因此养成推送和弹出偶数个寄存器的习惯以保持这一点是个好主意。 (例如,如果您在不确保 8 字节对齐的情况下调用 mallocstrlen 之类的库函数,则可能会再次遇到未定义的行为。)

【讨论】:

  • 谢谢! 8字节对齐可能与它有关。 strlen 函数是我自己设计的,并且确实按照您的描述工作。使用我刚刚从 c_ascz 获得的字符串,我的用户输入服务调用函数,它出于某种原因返回字符串长度加 2。在所有其他情况下,它会 rwturn 不带 null 的字符串长度。因此,在 c_ascz 之后,我减去 1 以使 R0 中的字符串长度 + 1。然后我 malloc 那个。然后在输入内部的存储函数结束时,我确实存储了空终止符。就像我说的那样,垃圾真的只出现在所有长度为 12 的字符串上
  • 不过 12 并没有什么魔力。也许尝试找出 +2 在您的字符串长度计算中来自哪里,而不是仅仅减去一个并希望得到最好的结果?
  • 我做到了,但我没有足够的帖子或其他任何内容,但谢谢!
最近更新 更多