Pergunta

Suponha que temos duas variáveis ​​inteiras e de caracteres:

int adad=12345;
char character;

Supondo que estamos discutindo uma plataforma na qual o comprimento de uma variável inteira é maior ou igual a três bytes, quero acessar o terceiro byte desse número inteiro e colocá-lo na variável de caractere, com isso dito eu escreveria como esse:

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

Considerando essa linha de código e o fato de não ser um compilador ou especialista em assembly, sei um pouco sobre como abordar modos em assembly e estou me perguntando o endereço do terceiro byte (ou acho que é melhor dizer deslocamento do terceiro byte) aqui estaria dentro das instruções geradas pela própria linha de código ou estaria em uma variável separada cujo endereço (ou desvio) está dentro dessas instruções?

Foi útil?

Solução

A melhor coisa a fazer em situações como essa é tentar.Aqui está um exemplo de programa:

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

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

  return 0;
}

Eu adicionei o volatile para evitar que a linha de atribuição seja completamente otimizada.Agora, aqui está o que o compilador criou (por -Oz no meu Mac):

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

As únicas três linhas com as quais nos preocupamos são:

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

O movl é a inicialização de adad.Então, como você pode ver, ele lê o terceiro byte do adad, e armazena-o de volta na memória (o volatile está forçando aquela loja a voltar).

Acho que uma boa pergunta é: por que é importante para você qual assembly é gerado?Por exemplo, apenas alterando meu sinalizador de otimização para -O0, a saída do assembly para a parte interessante do código é:

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

O que é visto de forma bastante direta como as operações lógicas exatas do seu código:

  1. Inicializar adad
  2. Pegue o endereço de adad
  3. Adicione 2 a esse endereço
  4. Carregue um byte desreferenciando o novo endereço
  5. Armazene um byte em character

Várias otimizações alterarão a saída...se você realmente precisar de algum modo de comportamento/endereçamento específico por algum motivo, talvez seja necessário escrever o assembly você mesmo.

Outras dicas

Sem saber nada sobre o compilador e a arquitetura subjacente da CPU, nenhuma resposta definitiva pode ser dada.Por exemplo, nem todas as arquiteturas de CPU permitem o endereçamento de cada byte arbitrário na memória (embora eu acredite que todas as arquiteturas atualmente populares o façam):em uma CPU endereçada a palavras, em vez de endereçada a bytes, o que o compilador irá gerar será inevitavelmente o carregamento em algum registro da palavra inteira adad (presumivelmente por um deslocamento de um registro de ponteiro base, se a variável em questão estiver na pilha [1]), seguido de deslocamento e mascaramento para isolar o byte de interesse.

[1] observe que, sem saber de qual arquitetura de CPU estamos falando e como o compilador a utiliza, não podemos nem dizer se "carregar uma palavra em um deslocamento fixo de um registro base" é algo que é feito inline dentro do instrução (como se poderia esperar, e muitas arquiteturas populares definitivamente suportam ;-) ou precisa de aritmética de endereço separada em um registro auxiliar.

IOW, seja uma boa ideia ou não, é definitivamente possível para definir uma arquitetura de CPU que não pode carregar/armazenar registros exceto de outros registros ou endereços de memória definidos por outros registros ou constantes, e algumas dessas arquiteturas existem (embora possam não ser tão populares no momento ;-).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top