当使用gcc -S选项编译C程序时,数组中的这个字符串如何用汇编表示?

时间:2015-11-30 07:51:41

标签: c gcc assembly

这是一个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

2 个答案:

答案 0 :(得分:6)

您正在使用函数main中的本地缓冲区,该字符串是从字符串文字初始化的。编译器将此初始化编译为将[rbp-32]的16个字节设置为3 mov条指令。第一个通过rax,第二个立即通过值为32位,第三个通过单个字节。

十进制的

8583909746840200520以十六进制为0x77202c6f6c6c6548,对应于小端序的字节"Hello, W"16848287830x646c726f,字节为{{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看到输入或循环边界是编译时常量。