用ARM汇编语言编写函数,该函数将字符串插入到特定位置的另一个字符串中

时间:2015-11-01 21:19:16

标签: c arm

我正在阅读我班级的一本教科书,我偶然发现了这个问题:

  

以ARM汇编语言编写函数,该函数将字符串插入特定位置的另一个字符串。功能是:       char * csinsert( char * s1, char * s2, int loc ) ;

     

该函数有一个指向a1中s1的指针,指向a2中s2的指针,以及a3中关于插入发生位置的整数。该函数将a1中的指针返回给新字符串。

     

您可以使用库函数strlen和malloc。       strlen输入指向a1中字符串的指针,并返回a1中的长度。       malloc将为新字符串分配空间,其中输入上的a1是所请求空间的字节大小,输出a1是指向所请求空间的指针。       请记住,寄存器a1-a4不会在函数调用中保留它们的值。

这是我创建的字符串插入的C语言驱动程序:

 #include <stdio.h>

extern char * csinsert( char * s1, char * s2, int loc ) ;
int main( int argc, char * argv[] )
{
char * s1 = "String 1 are combined" ;
char * s2 = " and string 2 " ;
int loc = 8 ;
char * result ;

result = csinsert( s1, s2, loc ) ;
printf( "Result: %s\n", result ) ;
}

到目前为止我的汇编语言代码是:

        .global csinsert
csinsert:
        stmfd sp!, {v1-v6, lr} 
        mov v1, a1             
        bl strlen              
        add a1, a1, #1         
        mov v2, a1
        add a2, a2
        mov v3, a2
        add a3, a3           
        bl malloc             
        mov v3, #0             
loop:           
        ldrb v4, [v1], #1       
        subs v2, v2, #1
        add v4, v4, a2         
        strb v4, [a1], #1                
        bne loop
        ldmfd sp!, {v1-v6, pc} @std
 .end

我认为我的代码无法正常运行。当我连接两个决赛时,没有给出结果。为什么我的代码没有正确插入字符串?我相信这个问题出在装配程序中,是不是没有返回任何内容?

任何人都可以解释我的错误是什么吗?我不知道如何使用问题提示的库函数。 谢谢!

1 个答案:

答案 0 :(得分:1)

警告:我已经做了40多岁的asm,我看了一下胳膊,但没有用过它。但是,我拉了手臂ABI文件。

正如问题所述,a1-a4在呼叫中保留,与ABI匹配。你保存了你的 a1,但你没有保存你的 a2或a3。

strlen [或任何其他函数]被允许使用a1-a4作为临时注册。因此,为了提高效率,我的猜测是strlen [或malloc]使用a2-a4作为临时和[从您的角度来看]破坏了一些寄存器值。

当你到达loop:时,a2可能是虚假旅程: - )

<强>更新

我开始清理你的asm。样式在asm中比C重要10倍。每个 asm行都应该有侧边栏注释。并在这里或那里添加一个空行。因为你没有发布你的更新代码,我不得不猜测这些变化,稍后,我意识到你只有大约25%左右。另外,我开始搞砸了。

我将问题分成三个部分:
- C中的代码 - 获取C代码并在C中生成arm伪代码 - asm中的代码

如果你看一下C代码和伪代码,你会注意到除了指令的任何误用,你的逻辑是错误的(例如你需要在strlen之前调用两次malloc

所以,这是你的汇编程序清理风格[没有太多新代码]。请注意,我可能已经破坏了一些现有逻辑,但我的版本可能更容易看到。我使用制表符来分隔事物并将所有内容排成一行。这可以帮助。此外,评论显示 intent 或说明指令或架构的限制。

.global csinsert
csinsert:

    stmfd   sp!,{v1-v6,lr}              // preserve caller registers

    // preserve our arguments across calls
    mov     v1,a1
    mov     v2,a2
    mov     v3,a3

    // get length of destination string
    mov     a1,v1                       // set dest addr as strlen arg
    bl      strlen                      // call strlen

    add     a1,a1,#1                    // increment length
    mov     v4,a1                       // save it

    add     v3,v3                       // src = src + src (what???)
    mov     v5,v2                       // save it

    add     v3,v3                       // double the offset (what???)

    bl      malloc                      // get heap memory

    mov     v4,#0                       // set index for loop

loop:
    ldrb    v7,[v1],#1
    subs    v2,v2,#1
    add     v7,v7,a2
    strb    v7,[a1],#1
    bne     loop

    ldmfd   sp!,{v1-v6,pc} @std         // restore caller registers

    .end

首先,你应该在真正的C中进行原型设计:

// csinsert_real -- real C code
char *
csinsert_real(char *s1,char *s2,int loc)
{
    int s1len;
    int s2len;
    char *bp;
    int chr;
    char *bf;

    s1len = strlen(s1);
    s2len = strlen(s2);

    bf = malloc(s1len + s2len + 1);
    bp = bf;

    // copy over s1 up to but not including the "insertion" point
    for (;  loc > 0;  --loc, ++s1, ++bp) {
        chr = *s1;
        if (chr == 0)
            break;
        *bp = chr;
    }

    // "insert" the s2 string
    for (chr = *s2++;  chr != 0;  chr = *s2++, ++bp)
        *bp = chr;

    // copy the remainder of s1 [if any]
    for (chr = *s1++;  chr != 0;  chr = *s1++, ++bp)
        *bp = chr;

    *bp = 0;

    return bf;
}

然后,你可以[直到你对手臂感到舒服],原型用C“伪代码”:

// csinsert_pseudo -- pseudo arm code
char *
csinsert_pseudo()
{

    // save caller registers

    v1 = a1;
    v2 = a2;
    v3 = a3;

    a1 = v1;
    strlen();
    v4 = a1;

    a1 = v2;
    strlen();

    a1 = a1 + v4 + 1;

    malloc();
    v5 = a1;

    // NOTE: load/store may only use r0-r7
    // and a1 is r0
#if 0
    r0 = a1;
#endif
    r1 = v1;
    r2 = v2;

    // copy over s1 up to but not including the "insertion" point
loop1:
    if (v3 == 0) goto eloop1;
    r3 = *r1;
    if (r3 == 0) goto eloop1;
    *r0 = r3;
    ++r0;
    ++r1;
    --v3;
    goto loop1;
eloop1:

    // "insert" the s2 string
loop2:
    r3 = *r2;
    if (r3 == 0) goto eloop2;
    *r0 = r3;
    ++r0;
    ++r2;
    goto loop2;
eloop2:

    // copy the remainder of s1 [if any]
loop3:
    r3 = *r1;
    if (r3 == 0) goto eloop3;
    *r0 = r3;
    ++r0;
    ++r1;
    goto loop3;
eloop3:

    *r0 = 0;

    a1 = v5;

    // restore caller registers
}