用 ARM 汇编语言编写一个函数,将一个字符串插入到另一个字符串的特定位置
writing a function in ARM assembly language which inserts a string into another string at a specific location
我正在阅读 class 的一本教科书,我偶然发现了这个问题:
Write a function in ARM assembly language which will insert a string into another string at a specific location. The function is:
char * csinsert( char * s1, char * s2, int loc ) ;
The function has a pointer to s1 in a1, a pointer to s2 in a2, and an integer in a3 as to where the insertion takes place. The function returns a pointer in a1 to the new string.
You can use the library functions strlen and malloc.
strlen has as input the pointer to the string in a1 and returns the length in a1.
malloc will allocate space for the new string where a1 on input is the size in bytes of the space requested and on output a1 is a pointer to the requested space.
Remember the registers a1-a4 do not retain their values across function calls.
这是我创建的用于插入字符串的 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
我认为我的代码无法正常工作。当我link 两场决赛时,没有给回结果。为什么我的代码没有正确插入字符串?我认为问题出在汇编程序中,它没有返回任何内容吗?
谁能解释一下我的错误是什么?我不确定如何使用问题提示的库函数。
谢谢!
警告:我从事 asm 工作已有 40 多年了,我稍微研究了一下 arm,但没有使用过它。不过,我拉取了arm ABI文档。
如问题所述,a1-a4 未 在调用中保留,这与 ABI 匹配。您保存了您的 a1,但是您没有保存您的 a2 或a3。
strlen
[或任何其他函数] 被允许使用 a1-a4 作为临时寄存器。因此,为了提高效率,我的猜测是 strlen
[或 malloc
] 正在使用 a2-a4 作为 scratch 并且 [从您的角度来看] 破坏了一些寄存器值。
当你到达 loop:
时,a2 可能是 虚假旅程 :-)
更新
我开始清理你的 asm。风格在 asm 中的重要性是 C 的 10 倍。Every asm 行应该有侧边栏注释。并在这里或那里添加一个空行。因为你没有 post 更新后的代码,我不得不猜测变化,过了一会儿,我意识到你只有大约 25% 左右。另外,我开始把事情搞砸了。
我把问题分成三个部分:
- C 中的代码
- 获取C代码并在C
中生成arm伪代码
- asm 中的代码
如果你看一下 C 代码和伪代码,你会注意到任何对指令的误用,你的逻辑是错误的(例如,你需要在 [=15= 之前调用两次 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 "pseudocode":
制作原型
// 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
}
我正在阅读 class 的一本教科书,我偶然发现了这个问题:
Write a function in ARM assembly language which will insert a string into another string at a specific location. The function is:
char * csinsert( char * s1, char * s2, int loc ) ;
The function has a pointer to s1 in a1, a pointer to s2 in a2, and an integer in a3 as to where the insertion takes place. The function returns a pointer in a1 to the new string.
You can use the library functions strlen and malloc. strlen has as input the pointer to the string in a1 and returns the length in a1. malloc will allocate space for the new string where a1 on input is the size in bytes of the space requested and on output a1 is a pointer to the requested space. Remember the registers a1-a4 do not retain their values across function calls.
这是我创建的用于插入字符串的 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
我认为我的代码无法正常工作。当我link 两场决赛时,没有给回结果。为什么我的代码没有正确插入字符串?我认为问题出在汇编程序中,它没有返回任何内容吗?
谁能解释一下我的错误是什么?我不确定如何使用问题提示的库函数。 谢谢!
警告:我从事 asm 工作已有 40 多年了,我稍微研究了一下 arm,但没有使用过它。不过,我拉取了arm ABI文档。
如问题所述,a1-a4 未 在调用中保留,这与 ABI 匹配。您保存了您的 a1,但是您没有保存您的 a2 或a3。
strlen
[或任何其他函数] 被允许使用 a1-a4 作为临时寄存器。因此,为了提高效率,我的猜测是 strlen
[或 malloc
] 正在使用 a2-a4 作为 scratch 并且 [从您的角度来看] 破坏了一些寄存器值。
当你到达 loop:
时,a2 可能是 虚假旅程 :-)
更新
我开始清理你的 asm。风格在 asm 中的重要性是 C 的 10 倍。Every asm 行应该有侧边栏注释。并在这里或那里添加一个空行。因为你没有 post 更新后的代码,我不得不猜测变化,过了一会儿,我意识到你只有大约 25% 左右。另外,我开始把事情搞砸了。
我把问题分成三个部分:
- C 中的代码
- 获取C代码并在C
中生成arm伪代码
- asm 中的代码
如果你看一下 C 代码和伪代码,你会注意到任何对指令的误用,你的逻辑是错误的(例如,你需要在 [=15= 之前调用两次 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 "pseudocode":
制作原型// 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
}