2013-03-05 8 views
6

я написал небольшую программу: грГде хранятся строковые данные?

#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

+0

Используйте команду 'strings' в вашем исполняемом файле ELF. – cdarke

ответ

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

+1

Используя таблицу [ASCII] (http://www.asciitable.com/). – pmg

+0

Почему, если я даю более длинную строку, она отображается в виде обычного текста, например: .string «очень длинная строка»? – kaspersky

3

Строка здесь:

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

Это копирует кучу значений в стек. Эти значения являются вашей строкой.

1

строка константы хранятся в двоичной форме вашего приложения. Именно там, где ваш компилятор.

1

Сборка не имеет понятия «строка». Таким образом, «строка» на самом деле является куском памяти. Строка хранится где-то в памяти (вплоть до компилятора), тогда вы можете манипулировать этим фрагментом данных, используя его адрес памяти (указатель).

Если строка константа, компилятор может хотите использовать его в качестве констант вместо того, чтобы хранить его в памяти, которая быстрее. Это ваше дело, как отметил Пол 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 

Одно можно сделать предположение о строковых литералов: если указатель инициализируется буквальным, он будет указывать на статический массив символов, состоявшейся где-то в памяти. В результате указатель действителен в любой части программы, например. вы можете вернуть указатель на строковый литерал, инициализированный в функции, и он все равно будет действителен.

Смежные вопросы