2013-02-22 1 views
0

Я читал по следующей серии статей: http://www.altdevblogaday.com/2011/11/09/a-low-level-curriculum-for-c-and-cOSX 64 бит C++ РАЗБОРКОЙ построчно

разобранном код, показанный и разобрали код, я умея производить во время работы один и тот же код меняться весьма значительно, и я не хватает понимания, чтобы объяснить различия.

Есть ли кто-нибудь, кто может пройти через него по строкам и, возможно, объяснить, что он делает на каждом шагу? Я получаю чувство от поиска вокруг, я сделал, что первые несколько строк имеют какое-то отношение к указателям на кадры, в моем дизассемблированном коде также есть несколько лишних строк, которые гарантируют, что регистры пустые, прежде чем помещать в них новые значения (отсутствует из кода в статье)

Я запускаю это на OSX (оригинальный автор использует Windows), используя компилятор g ++ из XCode 4. Я действительно не знаю, как погода или нет, эти отклонения связаны с ОС, (возможно, 32 бит или 64 бит) или сам компилятор. Это может быть даже код, который я предполагаю - мой обернут внутри объявления основной функции, тогда как исходный код не упоминает об этом.

Мой код:

int main(int argc, const char * argv[]) 
{ 

    int x = 1; 
    int y = 2; 
    int z = 0; 

    z = x + y; 

} 

Мой разобранном код:

0x100000f40: pushq %rbp 
0x100000f41: movq %rsp, %rbp 
0x100000f44: movl $0, %eax 
0x100000f49: movl %edi, -4(%rbp) 
0x100000f4c: movq %rsi, -16(%rbp) 
0x100000f50: movl $1, -20(%rbp) 
0x100000f57: movl $2, -24(%rbp) 
0x100000f5e: movl $0, -28(%rbp) 
0x100000f65: movl -20(%rbp), %edi 
0x100000f68: addl -24(%rbp), %edi 
0x100000f6b: movl %edi, -28(%rbp) 
0x100000f6e: popq %rbp 
0x100000f6f: ret  

разобранном код из оригинальной статьи:

mov dword ptr [ebp-8],1 
mov dword ptr [ebp-14h],2 
mov dword ptr [ebp-20h],0 
mov eax, dword ptr [ebp-8] 
add eax, dword ptr [ebp-14h] 
mov dword ptr [ebp-20h],eax 

Полная линия пробоем линии будет очень поучительно но любая помощь в понимании этого будет оценена по достоинству.

ответ

0

Существует два основных различия между вашим дизассемблированным кодом и кодом статьи.

Во-первых, в статье используется синтаксис ассемблера Intel, в то время как ваш дизассемблированный код использует традиционный синтаксис ассемблера Unix/AT & T. Некоторые различия между ними документируются на Wikipedia.

Другое отличие состоит в том, что в статье отсутствует пролог функции, который устанавливает фрейм стека и эпилог функции, который разрушает фрейм стека и возвращает вызывающему. Программа, которую он разбирает, должна содержать инструкции для выполнения этих задач, но его дизассемблер не показывает их. (На самом деле кадр стека может и, вероятно, будет опущено, если оптимизатор был включен, но это явно не включен.)

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

На Mac, г ++ не поддерживает излучающие Intel мнемоники, но лязг делает:

:; clang -S -mllvm --x86-asm-syntax=intel t.c 
:; cat t.s 
    .section __TEXT,__text,regular,pure_instructions 
    .globl _main 
    .align 4, 0x90 
_main:         ## @main 
    .cfi_startproc 
## BB#0: 
    push RBP 
Ltmp2: 
    .cfi_def_cfa_offset 16 
Ltmp3: 
    .cfi_offset rbp, -16 
    mov RBP, RSP 
Ltmp4: 
    .cfi_def_cfa_register rbp 
    mov EAX, 0 
    mov DWORD PTR [RBP - 4], EDI 
    mov QWORD PTR [RBP - 16], RSI 
    mov DWORD PTR [RBP - 20], 1 
    mov DWORD PTR [RBP - 24], 2 
    mov DWORD PTR [RBP - 28], 0 
    mov EDI, DWORD PTR [RBP - 20] 
    add EDI, DWORD PTR [RBP - 24] 
    mov DWORD PTR [RBP - 28], EDI 
    pop RBP 
    ret 
    .cfi_endproc 


.subsections_via_symbols 

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

.loc 1 4 14 prologue_end  ## t.c:4:14 
Ltmp5: 
    mov DWORD PTR [RBP - 20], 1 
    .loc 1 5 14     ## t.c:5:14 
    mov DWORD PTR [RBP - 24], 2 
    .loc 1 6 14     ## t.c:6:14 
    mov DWORD PTR [RBP - 28], 0 
    .loc 1 8 5     ## t.c:8:5 
    mov EDI, DWORD PTR [RBP - 20] 
    add EDI, DWORD PTR [RBP - 24] 
    mov DWORD PTR [RBP - 28], EDI 
2

Весь код из оригинальной статьи находится в вашем коде, там есть только некоторые дополнительные материалы. Это:

0x100000f50: movl $1, -20(%rbp) 
0x100000f57: movl $2, -24(%rbp) 
0x100000f5e: movl $0, -28(%rbp) 
0x100000f65: movl -20(%rbp), %edi 
0x100000f68: addl -24(%rbp), %edi 
0x100000f6b: movl %edi, -28(%rbp) 

Соответствует непосредственно 6 инструкциям, о которых говорится в статье.

0

Прежде всего, ассемблер, обозначенный как «из оригинальной статьи», использует синтаксис «Intel», где «дизассемблированный вывод» в вашем сообщении «AT 34 T синтаксис». Это объясняет порядок аргументов инструкциям «назад к фронту» [давайте не будем спорить о том, что правильно или неправильно, нормально?], А имена регистров префиксны с %, константами с префиксом $. Существует также разница в том, как привязаны ячейки памяти/смещения к реестрам - dword ptr [reg+offs] в Intel assembler переводит на l в качестве суффикса на инструкцию и offs(%reg).

32-разрядный и 64-разрядный переименовывает некоторые регистры - %rbp - это то же самое, что и код ebp.

Фактические смещения (например, -20) отличаются отчасти потому, что регистры больше в 64-битной, но и потому, что у вас есть argc и argv как часть ваших аргументов функции, которые хранятся как часть начала функции - У меня есть ощущение, что оригинальная статья на самом деле разбирает другую функцию, чем main.

+0

Спасибо за это - определенно прояснили некоторые вещи, которые я не понял! Тот факт, что это другой синтаксис, в целом объясняет многое, а также вашу точку зрения на разные смещения. – GeoffK

+0

Оригинальная статья кажется хорошо. На x86 «argc» и «argv» будут нажаты вызывающим и, следовательно, будут иметь * положительные * смещения относительно «ebp» (ebp + 0 - старый BP, ebp + 4 - обратный адрес, ebp + 8 - первый аргумент ...). В x86_64 OSX первые два аргумента передаются в 'rdi' (' edi' в этом случае, потому что это int) и 'rsi'. Похоже, что он был скомпилирован с '-O0', поэтому аргументы немедленно сохраняются в стеке. –

+0

Извините за то, что вы не поняли это, но как бы включить эти оптимизации? Было бы неплохо запустить его с/без и сравнить – GeoffK