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

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

使用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  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 

我认为我的代码不正常。 当我链接两个决赛时,没有给出结果。 为什么我的代码没有正确插入字符串? 我相信问题出在assembly程序中,是不是还没有返回任何东西?

谁能解释我的错误是什么? 我不知道如何使用问题提示的库函数。 谢谢!

警告:我一直在做40岁以上的asm,我看了一下胳膊,但没用过它。 但是,我拉了armABI文件。

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

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

当你开始loop: a2可能是一个虚假的旅程 🙂

UPDATE

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

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

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

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

 .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; } 

然后,你可以[直到你对arm感到舒服],用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 }