2013-03-05 178 views
6

我写了一个小的C程序:字符串数据存储在哪里?

#include <stdio.h> 

int main() 
{ 
    char s[] = "Hello, world!"; 
    printf("%s\n", s); 
    return 0; 
} 

其编译为(我的Linux机器上):

.file "hello.c" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    subq $32, %rsp 
    movq %fs:40, %rax 
    movq %rax, -8(%rbp) 
    xorl %eax, %eax 
    movl $1819043144, -32(%rbp) 
    movl $1998597231, -28(%rbp) 
    movl $1684828783, -24(%rbp) 
    movw $33, -20(%rbp) 
    leaq -32(%rbp), %rax 
    movq %rax, %rdi 
    call puts 
    movl $0, %eax 
    movq -8(%rbp), %rdx 
    xorq %fs:40, %rdx 
    je .L3 
    call __stack_chk_fail 
.L3: 
    leave 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size main, .-main 
    .ident "GCC: (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2" 
    .section .note.GNU-stack,"",@progbits 

我不明白的汇编代码,但我看不到任何地方字符串消息。那么可执行文件如何知道要打印什么?

+0

该字符串是内存中的常量,如果使用编辑器打开二进制文件,它甚至应该可见;然后通过在反汇编中可见的movl将数据复制到您的数组中。 – Dariusz 2013-03-05 12:17:44

+0

在您的ELF可执行文件上使用'strings'命令。 – cdarke 2013-03-05 12:31:15

回答

12

它在这里:

movl $1819043144, -32(%rbp) ; 1819043144 = 0x6C6C6548 = "lleH" 
movl $1998597231, -28(%rbp) ; 1998597231 = 0x77202C6F = "w ,o" 
movl $1684828783, -24(%rbp) ; 1684828783 = 0x646C726F = "dlro" 
movw $33, -20(%rbp)   ;   33 =  0x0021 = "\0!" 

在编译器生成内联的指令生成文本字符串调用printf前不变这种特殊情况下。当然,在其他情况下,它可能不会这样做,但可能会将字符串常量存储在另一部分内存中。底线:您不能对编译器将如何或在何处生成和存储字符串文字进行任何假设。

+0

如何将这些值解码为ASCII? – kamituel 2013-03-05 12:17:33

+1

通过使用[ASCII表格](http://www.asciitable.com/)。 – pmg 2013-03-05 12:20:22

+0

为什么如果我给一个更长的字符串,它显示为纯文本,如:.string“一个很长的字符串”? – kaspersky 2013-03-05 12:22:23

3

字符串是在这里:

movl $1819043144, -32(%rbp) 
movl $1998597231, -28(%rbp) 
movl $1684828783, -24(%rbp) 

此副本一堆值的堆栈。这些值恰好是你的字符串。

1

字符串常量存储在您的应用程序的二进制文件中。具体到哪里取决于你的编译器。

1

装配没有“字符串”的概念。因此,“字符串”实际上是一块内存。该字符串存储在内存中的某处(直到编译器),然后您可以使用其内存地址(指针)来处理这块数据。

如果你的字符串常量,编译器可能想用它作为常量,而不是将其存储到内存中,这是更快的。正如Paul R指出的那样,您的情况如下:

movl $1819043144, -32(%rbp) 
movl $1998597231, -28(%rbp) 
movl $1684828783, -24(%rbp) 

您无法对编译器如何处理字符串做出假设。

0

除上述内容外,编译器可以看到您的字符串文字不能被直接引用(即不能有任何有效的字符串指针),这就是为什么它可以直接复制它。然而,如果你指定一个字符指针代替,即

char *s = "Hello, world!";

,编译器会在内存中的某个地方初始化字符串文字,因为你当然可以现在指向它。此修改产生我的机器上:

.LC0: 
    .string "Hello, world!" 
    .text 
    .globl main 
    .type main, @function 

一个假设,可字符串文字进行:如果指针被初始化为文字,它会指向内存中的某个地方举行一个静态的字符数组。结果指针在程序的任何部分都是有效的,例如,你可以返回一个指向一个函数初始化的字符串的指针,它仍然是有效的。