这是一个C程序,已使用gcc -S
编译为程序集。字符串“Hello,world”如何在此程序中表示?
这是C代码:
1. #include <stdio.h>
2.
3. int main(void) {
4.
5. char st[] = "Hello, wolrd";
6. printf("%s\n", st);
7.
8. return 0;
9. }
下面是汇编代码:
1. .intel_syntax noprefix
2. .text
3. .globl main
4.
5. main:
6. push rbp
7. mov rbp, rsp
8. sub rsp, 32
9. mov rax, QWORD PTR fs:40
10 mov QWORD PTR [rbp-8], rax
11. xor eax, eax
12. movabs rax, 8583909746840200520
15. mov QWORD PTR [rbp-32], rax
14. mov DWORD PTR [rbp-24], 1684828783
15. mov BYTE PTR [rbp-20], 0
16. lea rax, [rbp-32]
17. mov rdi, rax
18. call puts
19. mov eax, 0
20. mov rdx, QWORD PTR [rbp-8]
21. xor rdx, QWORD PTR fs:40
22 je .L3
22. call __stack_chk_fail
23. .L3:
24. leave
25. ret
答案 0 :(得分:6)
您正在使用函数main
中的本地缓冲区,该字符串是从字符串文字初始化的。编译器将此初始化编译为将[rbp-32]
的16个字节设置为3 mov
条指令。第一个通过rax
,第二个立即通过值为32位,第三个通过单个字节。
8583909746840200520
以十六进制为0x77202c6f6c6c6548
,对应于小端序的字节"Hello, W"
,1684828783
为0x646c726f
,字节为{{1 }}。第三个mov设置最后的"orld"
字节。因此缓冲区包含“Hello,World”。
然后将此字符串传递给'\0'
以输出到puts
。
请注意,stdout
优化了对gcc
的通话printf("%s\n", "Hello, World");
!顺便说一句,puts("Hello, World");
执行相同的优化。
答案 1 :(得分:2)
有趣。
如果你写了const char *str="..."
,gcc就会在puts
部分传递.rodata
指向那里的字符串的指针,就像this godbolt link一样。 (chqrlie很好地发现gcc正在优化printf到put)。
您的代码强制编译器通过将其分配给非const char[]
来创建字符串文字的可写副本。 (实际上,即使使用const char str[]
,gcc仍会从mov-immediates动态生成它.clang-3.7 spots the chance to optimize,但是。)
有趣的是,它将其编码为即时数据,而不是复制到缓冲区中。如果数组是全局的,那么它就会坐在常规的.data
部分,而不是.rodata
。
此外,通常避免使用main()
来查看编译器优化。 gcc故意将其标记为&#34; cold&#34;,并将其优化得更少。这对于在其他功能中真正工作的真实程序来说是一个优势。在这种情况下没有区别,重命名为main。但通常如果你正在研究gcc如何优化某些东西,最好编写一个带有一些args的函数,并使用它们。然后你不必担心gcc看到输入或循环边界是编译时常量。