我在c中编写了一个程序并将其转换为arm程序集,现在我在理解汇编代码中生成的某些指令时遇到了问题。 C程序的一部分是:
#define MAX_DIGIT 1024
int main()
{
int fd[MAX_DIGIT];
int xLen = 0;
int sd[MAX_DIGIT];
int yLen = 0;
int result[6*MAX_DIGIT];
// Take input for two numbers
takeInput(fd, &xLen);
takeInput(sd, &yLen);
...
...
...
}
...
...
...
void takeInput(int digit[], int *length)
{
char c;
if((c=getchar()) != '\n' && *length <= MAX_DIGIT){
takeInput(digit, length);
digit[*length] = c - '0';
(*length)++;
}else return;
}
我已经使用gnu arm工具链将此c代码转换为arm汇编代码。生成的汇编代码的一部分是:
main:
@ args = 0, pretend = 0, frame = 32788
@ frame_needed = 1, uses_anonymous_args = 0
mov ip, sp
stmfd sp!, {fp, ip, lr, pc}
sub fp, ip, #4
sub sp, sp, #32768
sub sp, sp, #20 @Why subtracted 20?
mvn r3, #4096
sub r3, r3, #3
@What r3 storing and Why took NOT of r3 and again subtract 3 from it?
mov r2, #0
sub r0, fp, #12
str r2, [r0, r3]
mvn r3, #8192
sub r3, r3, #7
mov r2, #0
sub r1, fp, #12
str r2, [r1, r3]
sub r2, fp, #4096
sub r2, r2, #12
sub r3, fp, #4096
sub r3, r3, #12
sub r3, r3, #4
mov r0, r2
mov r1, r3
bl takeInput
sub r2, fp, #8192
sub r2, r2, #12
sub r2, r2, #4
sub r3, fp, #8192
sub r3, r3, #12
sub r3, r3, #8
mov r0, r2
mov r1, r3
bl takeInput
mvn r3, #32768
sub r3, r3, #11
mov r2, #1
sub ip, fp, #12
str r2, [ip, r3]
我在评论中已经在汇编代码中标记了我的想法。感谢。
答案 0 :(得分:6)
立即数(在指令的某些部分中编码的常数)只能具有某些值,因为编码它们的字段只有几位。当编译器想要加载一个值无法使用立即值编码的寄存器时,它会加载部分值,然后使用算术来完成它。
不同的ARM指令中存在不同的立即值编码,但这里有一个来自ARM体系结构参考手册,ARMv7-A和ARMv7-R版本的示例。 “ARM指令中的修改的立即数”被编码为12位。四位指定旋转,八位是该值的文字位。四位形成二进制数字,并且旋转量是该数字的两倍,在右侧。例如,如果四个比特是0011,即三个,则旋转量是六比特。
因此,如果四个旋转位是0011,并且八个文字位是10011101,则通过在32位字段内向右旋转10011101来形成该值。所以0000 0000 0000 0000 0000 0000 1001 1101向右旋转6位,产生0110 0100 0000 0000 0000 0000 0000 0010或0x64000002。
显然,12位不能编码所有可能的32位值。编译器在您的示例中需要的值之一是32748,即0x7fec。我们不能在任何位置从8位形成0x7fec(或者更具体地说,是偶数索引位置)。