ARM64-计算字符串长度

时间:2018-10-20 15:32:37

标签: assembly arm

我正在尝试编写一个程序,该程序读取字符串并计算其长度,以供以后在程序中使用。到目前为止,这就是我所拥有的。

    ldr x0, =stringread
    ldr x1, =strbuffer //string to be analyzed
    bl scanf

    mov x9, #0 //initialize length = 0
    bl Loop 

Loop:
    ldrb w11, [x1, x9] //load w11 with the x9th value of the string in x1
    cbnz w11, increment_length //until a 0 appears, continue iterating
                               //thru string while incrementing length
    /* what to put here to break the loop once zero is reached?*/

increment_length:
    add x9, x9, #0 
    bl Loop

我不确定如何打破这个循环。我会分支到另一个只是用来打破循环的分支吗?如标记为zero_reached的分支中一样?我目前遇到细分错误。任何提示或指示,将不胜感激。

(作为参考,这是我的整个程序。它尚未完成,我只需要过去计算长度即可继续到其他部分)。

    .data
outformat:     .asciz "%c"  
flush:          .asciz "\n"      
stringread:     .asciz "%s" 
lengthread:     .asciz "%d" 
strbuffer: .space 100       
lenbuffer: .space 8       

    .text
    .global main


main:       
    ldr x0, =prompt
    mov x1, x0
    bl printf

    ldr x0, =stringread
    ldr x1, =strbuffer
    bl scanf

    mov x9, #0 //length
    bl Loop

Loop:
    ldrb w11, [x1, x9]
    cmp w11, #0
    bne increment_length
    add x9, x9, #1

increment_length:
    add x9, x9, #0 
    bl Loop     

    #Change length to length-1
    sub x0, x0, #1 

    #Move string address to x1
    ldr x1, =strbuffer

    #Starting index for reverse
    mov x2, #0

    #Branch to reverse, setting return address
    bl reverse

    #Flush the stdout buffer
    ldr x0, =flush
    bl printf

    #Exit the program
    b exit

reverse:    #In reverse we want to maintain
            #x0 is length-1
            #x1 is memory location where string is
            #x2 is index

    subs x3, x2, x0

    #If we haven't reached the last index, recurse
    b.lt recurse

base:       #We've reached the end of the string. Print!
    ldr x0, =outformat

    #We need to keep x1 around because that's the string address!
    #Also bl will overwrite return address, so store that too
    stp x30, x1, [sp, #-16]!
    ldrb w1, [x1, x2]
    bl printf
    ldp x30, x1, [sp], #16

    #Go back and start executing at the return
    #address that we stored 
    br x30

recurse:    #First we store the frame pointer(x29) and 
            #link register(x30)
    sub sp, sp, #16
    str x29, [sp, #0]
    str x30, [sp, #8]

    #Move our frame pointer
    add x29, sp, #8

    #Make room for the index on the stack
    sub sp, sp, #16

    #Store it with respect to the frame pointer
    str x2, [x29, #-16]

    add x2, x2, #1 

    #Branch and link to original function. 
    bl reverse

    #Back from other recursion, so load in our index
end_rec:
    ldr x2, [x29, #-16]

    #Print the char!
    stp x30, x1, [sp, #-16]!
    ldr x0, =outformat
    ldrb w1, [x1, x2]
    bl printf
    ldp x30, x1, [sp], #16

    #Clear off stack space used to hold index
    add sp, sp, #16

    #Load in fp and lr
    ldr x29, [sp, #0]
    ldr x30, [sp, #8]

    #Clear off the stack space used to hold fp and lr
    add sp, sp, #16

    #Return to correct location in execution
    br x30

exit:
    mov x0, #0
    mov x8, #93
    svc #0

    .section .data

prompt:
    .asciz "input a string\n"

1 个答案:

答案 0 :(得分:0)

我不确定您使用的是哪个汇编程序,但是我可以说您并不总是正确地使用BLBL是“带链接的分支”,实际上是一条“调用”指令,在分支之前用所需的返回地址覆盖链接寄存器。有时候您正确使用(BL printf,有时没有正确使用(BL Loop,当您的意思仅仅是B Loop时)。

还请注意,“ Loop”标签的第一个分支是不必要的,因为它只是分支到下一条指令,并且您实际上并没有增加长度计数器(您要向其添加0!)。

我对您的循环代码段的建议如下:

    ldr x0, =stringread
    ldr x1, =strbuffer // String to be analyzed
    bl scanf

    mov x9, #0         // Initialize length = 0

Loop:
    ldrb w11, [x1, x9] // Load w11 with the x9th value of the string in x1
    cbz  w11, LoopEnd  // Until a 0 appears, continue iterating
    add  x9, x9, #1    // Increment x9
    b    Loop
LoopEnd:               // Continue from here

请注意,循环分支是无条件的,并且在循环开始处附近使用条件分支来对其进行转义。如果出现类似

的代码,这大约是C编译器将生成的内容
char * buffer = strbuffer;
int index = 0;
while (buffer[index] != 0) {
    ++index;
}

while循环顶部的条件在每个循环的开始进行评估,并且如果不满足,则会导致分支跳转到循环结束,就像上面的汇编语言代码一样。