2013-03-05 71 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 

一個假設,可字符串文字進行:如果指針被初始化爲文字,它會指向內存中的某個地方舉行一個靜態的字符數組。結果指針在程序的任何部分都是有效的,例如,你可以返回一個指向一個函數初始化的字符串的指針,它仍然是有效的。