Mostrando postagens com marcador lua format file. Mostrar todas as postagens
Mostrando postagens com marcador lua format file. Mostrar todas as postagens

domingo, 12 de fevereiro de 2012

Formato de Arquivo Lua

Nesse artigo vamos descrever a arquitetura interna de um arquivo compilado na linguagem Lua. Conhecendo a sua estrutura interna ajuda na construção de ferramentas como máquinas virtuais (Virtual Machines), programas case (Computer-Aided Software Engineering), otimizadores, interpretadores, etc. A versão utilizada é a 5.1.

Na figura a seguir, temos a visão macro de um arquivo compilado lua. Note que esse arquivo é composto por uma estrutura chamada de "Header" que significa cabeçalho, aonde estarão descritas informações gerais sobre a versão usada, tamanho das instruções, etc. E a outra estrutura, "Função" é a função nível Top ou Root (raiz) de um arquivo lua. Essa é a principal função desse arquivo lua compilado, quando a máquina virtual lua começa a execução do arquivo compilado, é essa função a primeira a ser executada e por padrão, essa função sempre existirá.



Note também que na figura está descrito "1 Header" que indica que existe apenas 1 (uma) estrutura do tipo Header. E da mesma maneira, "1 Função" indica que existe apenas 1 (uma) estrutura do tipo Função.

Vamos agora descrever a primeira estrutura do arquivo lua (Header). Na figura a seguir, temos os campos da estrutura Header que ocupa 12 bytes no início do arquivo lua.


Na próxima figura, descreveremos a estrutura "Função". Essa estrutura pode conter subfunções em forma de árvores na qual um pai tem N filhos mas o filho só pode ter um pai. E as subfunções seguem a mesma estrutura (campos, listas, etc) da função de nível top. Exceto para o campo "source name" que na função top terá o nome do arquivo fonte lua (extensão .lua) que originou o arquivo compilado. Para as demais subfunções, esse campo tem tamanho 0 (zero).


Nessa figura vemos que a função possuí estruturas simples como bytes e compostas (delimitadas por um retângulo ou "box"). Na figura a seguir, descreveremos a estrutura composta "Size_t" que será usada para definir o tamanho da estrutura "String" no arquivo compilado lua.


Nessa estrutura "Size_t" temos apenas N bytes para representar o tamanho de qualquer objeto. Esse "N" é fixo e está definido no campo "Tamanho do size_t" na estrutura Header. O padrão é 4 bytes, então N=4 bytes.

Na próxima figura, temos a estrutura "String" que armazena o objeto do tipo "string" (cadeia de caracteres) na linguagem lua. O campo do tipo "Size_t" armazena o tamanho da string lua. E o campo do tipo "N Bytes" armazena os caracteres e mais o caracter NUL (ASCII 0) no fim do array de bytes.


A próxima estrutura descrita será o "Integer" que é usado nas estruturas "Função", "Lista de Instruções", "Lista de Constantes", "Lista de Funções", "Lista de posições de linha de código", "Lista de variáveis locais", "Variável Local" e "Lista de upvalues". O campo do tipo "N Bytes" tem o tamanho definido no campo "Tamanho do int" na estrutura Header. Esse tamanho geralmente é de 4 bytes, fazendo N=4 bytes. Essa estrutura armazena o número inteiro usado em todo arquivo compilado lua.


A próxima subestrutura da estrutura "Função" é a lista de instruções lua (Lista de instruções). É nessa lista que temos todas as instruções lua para executar a própria função. A próxima figura mostra o conteúdo dessa lista de instruções. O campo do tipo "Integer" armazena o número de instruções presentes na lista. E o campo do tipo "N Instruções" armazena as instruções a serem usadas na execução da função lua.


Na figura a seguir, estará descrito o conteúdo da instrução lua.
A instrução lua apenas armazena um array de bytes cujo comprimento está definido no campo "Tamanho da instrução" da estrutura Header, geralmente o tamanho usado é 4 bytes, então N=4 bytes.


A próxima figura descreve a "Lista de constantes", essa lista armazena todas as constantes usadas durante a codificação do programador no arquivo fonte lua. Essas constantes são de 4 tipos básicos: nil, boolean, number e string. O primeiro campo do tipo "Integer" define o número de constantes contidas nessa lista. 


A constante em si será mostrada na próxima figura. O primeiro campo "1 byte" define o tipo da constante e o tamanho do próximo campo (a constante em si) estará em função do tipo definido no primeiro campo. Por exemplo, para a constante do tipo 0 (nil), o segundo campo (Const) não existirá (ou de tamanho zero). Para a constante do tipo 1 (boolean), o segundo campo (Const) será de tamanho 1 byte. Para a constante do tipo 3 (lua number), o segundo campo será do tamanho do número lua definido no Header, geralmente de 8 bytes. E por último, para a constante do tipo 4 (string), o tamanho é definido pelo comprimento da própria string.


O próximo campo da estrutura "Função" é a "Lista de funções" e nessa estrutura está contida todas as subfunções que a função possui. O campo do tipo "Integer" define o número de subfunções e o campo "N Funções" define N subfunções dentro da função.



Campos opcionais da estrutura "Função" que são usados para depuração (debug).

Os campos "Lista de posições de linha de código", "Lista de variáveis locais" e "Lista de upvalues" são estruturas usadas para realizar depuração (debug) no código e essas mesmas podem ser descartadas através do uso de um parâmetro (-s) no compilador lua (luac).

A estrutura "Lista de posições de linha no código" armazena todas as posições no código fonte para serem usadas na depuração (mais detalhes na próxima figura).


A estrutura "Lista de variáveis locais" armazena as variáveis locais (identificadores e escopo) para serem usadas na depuração (debug).


A estrutura "Variável local" armazena o nome (identificador) da variável local (definida no código fonte pelo programador) e o escopo. Esse "escopo" é definido pelo PC (Program Counter) de início do escopo da variável (segundo campo) e pelo PC de fim do escopo da variável.


A estrutura "Lista de upvalues" armazena todos os nomes das variáveis upvalues usadas no programa para depuração (debug).



Referências