Como arrays são representados em Assembly e o que muda na passagem de parâmetros em arquiteturas X64

Um array é um conjunto de valores posicionados na memória de maneira sequencial. Percorrer os elementos de um array implica, pura e simplesmente, em acessar essas posições memória.

Esse conceito, aliás, é bem explícito em C++.

#include <iostream>

using namespace std;

extern "C" int compute_sum_asm(const int* values, const int count);

int compute_sum(const int* values, const int count)
{
	auto result = 0;
	for (auto i = 0; i < count; i++)
	{
		result += *values;
		values++;
	}
	return result;
}

int main()
{
	const int values[] { 4, 7, 9, 12, 23, 18, 45 };
	const int count = sizeof(values) / sizeof(int);

	cout << compute_sum(values, count) << endl;
	cout << compute_sum_asm(values, count) << endl;

	return 0;
}

No exemplo, escrito de maneira bem primitiva, vemos que a função recebe dois parâmetros. O primeiro, é um ponteiro para o primeiro elemento no array. O segundo, é um contador indicando quantos elementos o array possui.

A implementação, em Assembly para x86 não se afasta muito do que já fizemos até aqui.

	.model flat, c
	.code

compute_sum_asm proc

	push ebp
	mov ebp, esp
	push ebx

	xor eax, eax

	mov ebx, [ebp + 8]
	mov edx, [ebp + 12]

	cmp edx, 0
	jle done

lp: add eax, [ebx]
	add ebx, 4
	dec edx
	jnz lp

done:
	pop ebx
	pop ebp
	ret

compute_sum_asm endp
	end 

Para X64, entretanto, essa implementação precisaria ser um pouco diferente. Com o número ampliado de registradores (todos que começam com “r” são versões 64 bits), a convenção os utiliza sempre que possível reduzindo a utilização da Stack. Como registradores são os elementos de memória mais velozes disponíveis, o resultado é um incremento de performance.

Convenções para chamada de funções em C++ 64 bits

A convenção para chamada de funções em C/C++ X64 se beneficia do número maior de registradores disponível nessa arquitetura. Assim:

  • Os primeiros quatro parâmetros inteiros ou ponteiros são passados através dos registradores rcx, rdx, r8, e r9.
  • Os primeiros quatro argumentos com ponto-flutuante são passados nos registradores SSE  xmm0xmm3.
  • A função que está “chamando” é responsável por reservar espaço na stack para os argumentos passados como parâmetros. Assim, a função “chamada” pode usar este espaço para “copiar” os valores dos registradores na stack.
  • Parâmetros adicionais são passados via stack.
  • O retorno deve acontecer em rax (lembrando que eax corresponde aos bits menos significativos desse registrador). Retornos com ponto flutuante devem ser retornados em xmm0.
  • rax, rcx, rdx, r8r11 são voláteis (não é necessário garantir que seus valores sejam restaurados quando a função retorna).
  • rbx, rbp, rdi, rsi, r12r15 não são voláteis..

Fonte: Microsoft

Essas convenções, por interoperabilidade, também são respeitadas pelo .NET

No exemplo desse post, como estamos passando um ponteiro e um inteiro, respectivamente, os registradores utilizados  nas passagens de parâmetros são rcx e rdx.

       .code

compute_sum_asm proc
	xor eax, eax

	cmp edx, 0
	jle done
	
lp: add eax, [rcx]
	add rcx, 4
	dec edx
	jnz lp

done: 	
	ret

compute_sum_asm endp

	end 

Os cuidados no projeto dos compiladores em aproveitar as características da arquitetura de execução são expressão de “design caprichoso”.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
0 Comentários
Inline Feedbacks
View all comments

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
0
Queremos saber a sua opinião, deixe seu comentáriox
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Como arrays são representados em Assembly e o que muda na passagem de parâmetros em arquiteturas X64

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Como arrays são representados em Assembly e o que muda na passagem de parâmetros em arquiteturas X64

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?