当我用gcc -S从C代码创建ARM汇编代码时,我得到了一个我不知道的LDR指令的变体。具体来说,我得到了"ldr r3,.L5“指令,其中".L5”是编译器定义的一个lable。我不清楚为什么我没有得到伪指令"ldr r3,=.L5",这应该是在寄存器中加载任意数字的唯一方法。
详情如下:
我从这个C代码开始(文件名: sum_squares_C.c): )
int sum;
int main(){
sum = 0;
for(int i=1; i<=n; i++){
sum = sum + i*i;
}
} .arch armv6
.eabi_attribute 28, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "sum_squares_C.c"
.text
.global n
.data
.align 2
.type n, %object
.size n, 4
n:
.word 1
.comm sum,4,4
.text
.align 2
.global main
.arch armv6
.syntax unified
.arm
.fpu vfp
.type main, %function
main:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #12
ldr r3, .L5
mov r2, #0
str r2, [r3]
mov r3, #1
str r3, [fp, #-8]
b .L2
.L3:
ldr r3, [fp, #-8]
ldr r2, [fp, #-8]
mul r2, r2, r3
ldr r3, .L5
ldr r3, [r3]
add r3, r2, r3
ldr r2, .L5
str r3, [r2]
ldr r3, [fp, #-8]
add r3, r3, #1
str r3, [fp, #-8]
.L2:
ldr r3, .L5+4
ldr r3, [r3]
ldr r2, [fp, #-8]
cmp r2, r3
ble .L3
mov r3, #0
mov r0, r3
add sp, fp, #0
@ sp needed
ldr fp, [sp], #4
bx lr
.L6:
.align 2
.L5:
.word sum
.word n
.size main, .-main
.ident "GCC: (Raspbian 8.3.0-6+rpi1) 8.3.0"
.section .note.GNU-stack,"",%progbits在我看来,gcc使用的指令"ldr r3,.L5“相当于"ldr r3,=.L5”。这是正确的吗?在哪里可以找到这个指令语法的定义?有没有可能强迫gcc不使用这个指令,而是使用"ldr r3,=.L5“(因为教学原因我需要这个)?
谢谢!弗朗西斯科
发布于 2020-01-29 11:49:59
ldr r3, .L5将地址.L5中的一个单词加载到r3中。在标签.L5中,有变量sum的地址。因此,这将sum的地址加载到r3中。
ldr r3, =.L5将.L5的地址加载到r3中。然后,为了获得sum的地址,程序需要再次取消引用。没有理由这么做。
当您使用ldr r3, =.L5时,汇编程序会将.L5的地址存储在某个地方,然后从该地址加载。所以这个:
ldr r3, =.L5
...
.L5:
.word sum与此相同:
ldr r3, .address_of_L5
...
.L5:
.word sum
...
.address_of_L5:
.word .L5如您所见,编译器已经为sum完成了此操作。而不是编写此程序集:
ldr r3, =sum编译器编写了:
ldr r3, .L5
...
.L5:
.word sum这正是汇编程序应该做的。我不知道为什么编译器想要这样做,而不是汇编程序。
我不清楚为什么我没有得到伪指令"ldr r3,=.L5",这应该是在寄存器中加载任意数字的唯一方法。
注意,这不是将任意数字加载到寄存器中的唯一方法。它甚至不是将任意数字加载到寄存器中的真正方法。这是一种伪指令(如您所知):这不是CPU实际能做的事情,而是汇编程序为了您的方便可以“编译”的东西。
发布于 2020-01-29 12:48:42
为了节省打字并承担一个人可能使用的风险:
ldr r3,=sum
ldr r3,[r3]正如在另一个示例中所指出的,汇编程序将在机器代码中创建相当于人类可以在不使用=address技巧的情况下输入的内容:
ldr r3,address_of_sum (without the =)
ldr r3,[r3]
...
address_of_sum: .word sum而第一个ldr (不是伪的,因为它直接转换成一个已知的指令,一对一)是一个pc相对负载(假设它可以到达)。
这两种语言都是特定于汇编程序的,因为汇编语言是由汇编程序定义的,而不是目标。
地址快捷方式并不是所有arm汇编程序都支持的,应该谨慎使用,对于某些值,它不会在池中变成一个带有pc相对负载的单词。
对于像这样的问题,首先检查拆卸,大部分时间将回答您的问题,甚至更好地先检查拆卸程序集,然后再检查程序集。编译器生成的程序集不像反汇编那样容易读取和跟踪,特别是在链接时。与未优化的代码相比,从优化的代码中学习也更容易,因为大部分代码都是堆栈(在本例中是全局的)变量。
ldr r3,=0x1000
ldr r3,=0x1234
b .
00000000 <.text>:
0: e3a03a01 mov r3, #4096 ; 0x1000
4: e51f3000 ldr r3, [pc, #-0] ; c <.text+0xc>
8: eafffffe b 8 <.text+0x8>
c: 00001234 andeq r1, r0, r4, lsr r2在一种情况下,它可以生成一个mov,在那里它不能然后从池中分配值并将值放在那里,然后进行pc相对负载。现在,是的,当以这种方式读取输出时,您需要看到/理解/忽略andeq反汇编--我们正在查看0x00001234的值,并看到生成的指令。
如果您选择尝试各种工具,您不应该总是假设=address技巧会起作用,如果它现在可以找到一个池(如果它找不到),那么您需要自己输入,或者添加一个.pool,或者任何其他伪代码来帮助汇编程序根据需要为这个值找到一个位置。
我希望汇编程序总是将它(=address)放置在池中,以便进行外部引用,但从技术上讲,工具链可以将占位符放在其中,让链接器使用mov或添加附近的项来填充它,并像binutils一样将值放置到外部引用中。
气体:
ldr r3,=sum
b .
00000000 <.text>:
0: e51f3000 ldr r3, [pc, #-0] ; 8 <.text+0x8>
4: eafffffe b 4 <.text+0x4>
8: 00000000 andeq r0, r0, r0链接器将在稍后的编译器输出中填写地址。现在的-0拆卸是非常有趣的,几乎有趣。
https://stackoverflow.com/questions/59966245
复制相似问题