каким будет режим адресации в ассемблере, сгенерированном компилятором? - PullRequest
0 голосов
/ 07 августа 2010

Предположим, у нас есть две целочисленные и символьные переменные:

int adad=12345;
char character;

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

character=*((char *)(&adad)+2);

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

Ответы [ 2 ]

3 голосов
/ 07 августа 2010

Лучшее, что можно сделать в подобных ситуациях - это попробовать.Вот пример программы:

int main(int argc, char **argv)
{
  int adad=12345;
  volatile char character;

  character=*((char *)(&adad)+2);

  return 0;
}

Я добавил volatile, чтобы избежать полной оптимизации строки назначения.Теперь вот что придумал компилятор (для -Oz на моем Mac):

_main:
    pushq   %rbp
    movq    %rsp,%rbp
    movl    $0x00003039,0xf8(%rbp)
    movb    0xfa(%rbp),%al
    movb    %al,0xff(%rbp)
    xorl    %eax,%eax
    leave
    ret

Нам нужны только три строки:

    movl    $0x00003039,0xf8(%rbp)
    movb    0xfa(%rbp),%al
    movb    %al,0xff(%rbp)

movl это инициализация adad.Затем, как вы можете видеть, он считывает 3-й байт adad и сохраняет его обратно в память (volatile принудительно возвращает это хранилище).

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

    movl    $0x00003039,0xf8(%rbp)
    leaq    0xf8(%rbp),%rax
    addq    $0x02,%rax
    movzbl  (%rax),%eax
    movb    %al,0xff(%rbp)

Что довольно просто воспринимается как точные логические операции вашего кода:

  1. Инициализация adad
  2. Взять адрес adad
  3. Добавить 2 к этому адресу
  4. Загрузить один байт, разыменовав новый адрес
  5. Сохранение одного байта в character

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

2 голосов
/ 07 августа 2010

Не зная ничего о компиляторе и базовой архитектуре ЦП, однозначного ответа дать нельзя.Например, не все архитектуры ЦП допускают адресацию каждого произвольного байта в памяти (хотя я полагаю, что это делают все популярные в настоящее время): на ЦП с адресацией по словам вместо адреса с байтами неизбежно будет генерироваться то, что будет генерировать компилятор.быть загрузкой в ​​некоторый регистр целого слова adad (предположительно, смещением от регистра базового указателя, если рассматриваемая переменная находится в стеке [1]), с последующим сдвигом и маскированием для выделения интересующего байта.

[1] обратите внимание, что, не зная, о какой архитектуре ЦП мы говорим и как ее использует компилятор, мы даже не можем сказать, является ли «загрузка слова с фиксированным смещением от базового регистра»что-то, что делается внутри инструкции (как можно надеяться, и многие популярные архитектуры определенно поддерживают ;-) или нуждаются в отдельной адресной арифметике во вспомогательном регистре.

IOW, хорошая идея это или нет, этоопределенно возможно определить архитектуру процессора, которая можетне загружать / хранить регистры, кроме как из других регистров или адресов памяти, определенных другими регистрами или константами, и некоторые такие архитектуры существуют (хотя они могут быть не столь популярны в настоящее время; -).

...