20_LESI Posted June 18, 2009 at 11:46 PM Report Share #273505 Posted June 18, 2009 at 11:46 PM Provavelmente pouca gente usa disto, mas aqui vai a dúvida: Tenho de gerar o código Y86 do seguinte programa em C: typedef int mytype; mytype array[100]; int sum, i; void ini (void) { for (i=0 ; i<100 ; i++) array[i] = i; } main () { ini (); sum = 0; for (i=0 ; i<100 ; i++) sum += array[i]; } E eis a resolução do prof, para facilitar um bocado a coisa: .pos 0 irmovl Pilha, %esp rrmovl %esp, %ebp jmp main .pos 20 array: .pos 420 sum: .long 0 i: .long 0 ini: # --------------------- pushl %ebp rrmovl %esp, %ebp irmovl 4, %edx subl %edx, %esp #1 – push registos irmovl $0, %edx rmmovl %edx, -4(%ebp) for1: irmovl $100, %ecx subl %edx, %ecx #100-j jle fim_for1 rrmovl %edx, %eax addl %eax, %eax addl %eax, %eax rmmovl %edx, array(%eax) irmovl $1, %eax addl %eax, %edx rmmovl %edx, -4(%ebp) jmp for1 fim_for1: #2 – pop registos rrmovl %ebp, %esp popl %ebp ret main: # --------------------- call ini irmovl $0, %ebx rmmovl %ebx, sum(%ebx) rmmovl %ebx, i(%ebx) for2: irmovl $100, %ecx subl %ebx, %ecx # 100-i jle fim_for2 rrmovl %ebx, %eax addl %eax, %eax addl %eax, %eax mrmovl array(%eax), %edx irmovl $0, %esi mrmovl sum(%esi), %ecx addl %edx, %ecx rmmovl %ecx, sum(%esi) irmovl $1, %eax addl %eax, %ebx rmmovl %ebx, i(%esi) jmp for2 fim_for2: halt # --- espaço pilha --------- .pos 800 Pilha: Tenho vindo a estudar e a compreender a pouco e pouco como isto funciona, ainda assim, não csg entender o que se está a fazer quando se faz: rmmovl %edx, -4(%ebp) que ocorre antes do for1, e dentro do for1 Obrigado pela disponibilidade Link to comment Share on other sites More sharing options...
Rui Carlos Posted June 19, 2009 at 09:16 AM Report Share #273547 Posted June 19, 2009 at 09:16 AM Não percebo muito de Assembly, mas penso que tem a ver com a variável i. Coloca i a 0: irmovl $0, %edx rmmovl %edx, -4(%ebp) Soma 1 ao i: irmovl $1, %eax addl %eax, %edx rmmovl %edx, -4(%ebp) Esse rmmovl deve estar a passar o valor do i do registo para memória. Rui Carlos Gonçalves Link to comment Share on other sites More sharing options...
edsousa Posted June 19, 2009 at 10:02 AM Report Share #273558 Posted June 19, 2009 at 10:02 AM Anotei o code com as instr. C .pos 0 irmovl Pilha, %esp rrmovl %esp, %ebp jmp main .pos 20 # inicio do array array: .pos 420 sum: .long 0 # outras vars. globais i: .long 0 ini: # --------------------- pushl %ebp ## guardar o base pointer antigo o call frame rrmovl %esp, %ebp irmovl 4, %edx ## criar um espaço no stack frame subl %edx, %esp #1 – push registos irmovl $0, %edx ## i=0 rmmovl %edx, -4(%ebp) ## e mantê-lo numa var. local !!BUG, ela é global for1: irmovl $100, %ecx ## subl %edx, %ecx #100-j ## %edx<100, o seja o i, já chegou a 100 jle fim_for1 # se o 100 for menor ou igual a i, salta para o fim rrmovl %edx, %eax addl %eax, %eax ## eax = 4*i, ou seja, i*sizeof(int) addl %eax, %eax rmmovl %edx, array(%eax) # array[i] = i irmovl $1, %eax addl %eax, %edx # i++; rmmovl %edx, -4(%ebp) # store do i no espaço da var local jmp for1 # repeat fim_for1: #2 – pop registos rrmovl %ebp, %esp # restaurar o estado para sair da func. popl %ebp ret main: # --------------------- call ini irmovl $0, %ebx rmmovl %ebx, sum(%ebx) # sum=0 rmmovl %ebx, i(%ebx) # i=0 !! Aqui já se usa o sitio certo do i for2: irmovl $100, %ecx subl %ebx, %ecx # 100-i # i<100? jle fim_for2 # if not, jump fim_for2 rrmovl %ebx, %eax # eax=i; addl %eax, %eax addl %eax, %eax ##eax *= 4 mrmovl array(%eax), %edx # edx = array[i] ## irmovl $0, %esi ## mrmovl sum(%esi), %ecx # ecx = sum ## sum = sum + array[i] addl %edx, %ecx # ecx += edx ## rmmovl %ecx, sum(%esi) # sum = edx ## irmovl $1, %eax addl %eax, %ebx ## i++ rmmovl %ebx, i(%esi) # guardar o i jmp for2 # repeat fim_for2: halt # end # --- espaço pilha --------- .pos 800 Pilha: Tharis Fan ClubMay Tharis bless you Link to comment Share on other sites More sharing options...
20_LESI Posted June 19, 2009 at 10:36 AM Author Report Share #273573 Posted June 19, 2009 at 10:36 AM Não percebo muito de Assembly, mas penso que tem a ver com a variável i. Coloca i a 0: irmovl $0, %edx rmmovl %edx, -4(%ebp) Soma 1 ao i: irmovl $1, %eax addl %eax, %edx rmmovl %edx, -4(%ebp) Esse rmmovl deve estar a passar o valor do i do registo para memória. Exacto! Mas eu não via utilidade nenhuma nisso! Além de não perceber o porquê de guardar na stack. Mas penso que o post do edsousa me ajudou a perceber uma coisa muito importante: estou a ver a solução de uma outra versão do exercício, em que na funçao ini existe uma variável local 'j' que é usada em detrimento da variável global 'i': void ini (void) { for (j=0 ; j<100 ; j++) array[j] = j; } Ainda assim, continuo sem perceber o porquê de ser necessário guardar a variável 'i' em memória, ainda para mais na stack. rmmovl %edx, -4(%ebp) Dado que se tira -4 ao endereço contido em %ebp, como o sp neste caso aponta para um endereço imediatamente abaixo de %ebp, estou a meter o valor de %edx lá, certo? Link to comment Share on other sites More sharing options...
Rui Carlos Posted June 19, 2009 at 10:56 AM Report Share #273577 Posted June 19, 2009 at 10:56 AM Sendo a variável j global, precisarias de a guardar em memória. Se for local, será uma questão de má optimização de código. Mas nesse código que mostras, continuas sem ter a variável como local. Rui Carlos Gonçalves Link to comment Share on other sites More sharing options...
20_LESI Posted June 19, 2009 at 12:40 PM Author Report Share #273596 Posted June 19, 2009 at 12:40 PM Sendo a variável j global, precisarias de a guardar em memória. Se for local, será uma questão de má optimização de código. Mas nesse código que mostras, continuas sem ter a variável como local. Enganei-me! Esqueci-me da inicialização... Mas acho que já percebi isto! Obrigado aos 2!!! Link to comment Share on other sites More sharing options...
edsousa Posted June 19, 2009 at 12:56 PM Report Share #273599 Posted June 19, 2009 at 12:56 PM tens exame na segunda de manhã, não tens? Tharis Fan ClubMay Tharis bless you Link to comment Share on other sites More sharing options...
Guest id194 Posted June 21, 2009 at 02:12 AM Report Share #273849 Posted June 21, 2009 at 02:12 AM Deve ter e eu também e como tive o dia todo a estudar este exercício, mais propriamente a tentar perceber como é que tudo funciona a nível da stack e tal, tenho aqui uma solução um pouco diferente da apresentada e como o assunto é exactamente o mesmo, aproveito o tópico. Alguém que perceba do assunto e tenha paciência, agradecia imenso que desse uma revisão no seguinte código totalmente comentado por mim da forma que eu entendi o dito cujo pois não queria chegar ao teste e fazer as coisas mal... http://i40.tinypic.com/2niw5uc.jpg E uma nota sobre o código: 4(0xBP): Esta expressão representa o endereço de memória apontado por %ebp mais 4 e não o endereço '0xBP'. ie: %ebp = 0x0020 ou seja 4(0x0020) = 0x0024 Link to comment Share on other sites More sharing options...
20_LESI Posted June 21, 2009 at 11:10 AM Author Report Share #273868 Posted June 21, 2009 at 11:10 AM tens exame na segunda de manhã, não tens? Tenho 😄 Alguém sabe como transcrever isto para Y86? int main(int argc, char **argv) { int i, j=10; i = j*4; } Link to comment Share on other sites More sharing options...
Guest id194 Posted June 21, 2009 at 12:24 PM Report Share #273875 Posted June 21, 2009 at 12:24 PM A minha tentativa: .pos 0 irmovl Stack, %esp rrmovl %esp, %ebp i: .long 0 j: .long 0 main: irmovl $10, %ebx // %ebx = 10 irmovl i, %esi // %esi = 0xi (endereço de 'i') rmmovl %ebx, 4(%esi) // 4(%esi) = 10 (j = 10) addl %ebx, %ebx // %ebx = %ebx + %ebx <=> %ebx = 10 + 10 = 20 addl %ebx, %ebx // %ebx = %ebx + %ebx <=> %ebx = 20 + 20 = 40 rmmovl %ebx, 0(%esi) // 0(%esi) = 40 (i = 40 <=> i = j*4) halt .pos 50 Stack: .long 0 Problemas: Não faço ideia qual seria o procedimento para guardar o argc e o argv, principalmente o argv que vai depende do valor de argc. As variáveis i e j estão a ser usadas como globais e não locais, não faço ideia como se faz de outra forma. Fora isto, acho que fiz bem... 😄 Link to comment Share on other sites More sharing options...
20_LESI Posted June 21, 2009 at 12:53 PM Author Report Share #273882 Posted June 21, 2009 at 12:53 PM Problemas: Não faço ideia qual seria o procedimento para guardar o argc e o argv, principalmente o argv que vai depende do valor de argc. As variáveis i e j estão a ser usadas como globais e não locais, não faço ideia como se faz de outra forma. Fora isto, acho que fiz bem... 😄 As minhas dúvidas são relativas à passagem de parâmetros. O resto sei fazer. Quanto às variáveis locais, tens de as meter na stack e não torná-las globais, se bem que pouco mais além da teoria sobre isso eu sei.... Um outro exemplo que não me bate certo no simulador: int f(int p) { int j, ret = 1; for (j=p ; j>1 ; j--) ret *= j; return ret; } int main() { f(3); } Codifiquei isto da seguinte forma em assembly: .pos 0 irmovl Stack, %esp rrmovl %esp, %ebp jmp main .pos 20 f: pushl %ebp # salva %ebp rrmovl %ebp, %esp # inicializa a stack frame da função f irmovl 1, %eax # ret = 1 irmovl 8, %ecx # guarda o espaço a reservar para variáveis locais num registo subl %ecx, %esp # reservar espaço para variáveis locais rmmovl %eax, -4(%ebp) # guarda o valor de ret na stack mrmovl 8(%ebp), %ecx # j = p (vai buscar o parâmetro p) rmmovl %ecx, -8(%ebp) # guarda o valor de j na stack for1: irmovl 1, %edx rrmovl %ecx, %eax # salvaguarda o valor da variável j dentro do ciclo subl %edx, %ecx # j=j-1 jle fim_for1 mrmovl -4(%ebp), %edx # vai à stack buscar o valor da variável ret addl %ecx, %eax # ret = j+ret rmmovl %eax, -4(%ebp) # guardar o valor da variável ret na stack jmp for1 fim_for1: rrmovl %ebp, %esp popl %ebp ret # o valor de ret já se encontra na variável a, logo podemos retornar main: irmovl 3, %ebx pushl %ebx call f halt .pos250 Stack: Parecia-me estar correcto, mas a partir da linha: rmmovl %eax, -4(%ebp) # guarda o valor de ret na stack Começo a apagar valores que tenho na stack e que vou precisar mais tarde deles... Alguém sabe o que estou a fazer mal? Link to comment Share on other sites More sharing options...
Guest id194 Posted June 21, 2009 at 01:24 PM Report Share #273886 Posted June 21, 2009 at 01:24 PM Não vejo onde é que essa linha estaria mal, com as linhas irmovl 8, %ecx e subl %ecx, %esp estás a guardar espaço para o j e o ret, correcto? E de seguida usas o -4 para aceder ao ret e -8 para o j, acho que está bem... Eu acho é que estas a fazer mal no p porque o p também vai ser uma variável local que recebe o valor quando f é chamado. Logo, acho que te falta reservar algum espaço na stack (dentro do stack frame de f) para o p. O que eu fazia, era remover o pushl %ebx do main e coloca-lo no f logo a seguir a inicialização da stack, acho que faz mais sentido porque o p é local. Voltando ao problema inicial a ver se percebi o que disseste, para remover as variáveis locais tenho de as meter na stack, será assim: .pos 0 irmovl Stack, %esp rrmovl %esp, %ebp main: irmovl $8, %ebx ; %ebx = 8 subl %ebx, %esp ; %esp = %esp - %ebx (guarda espaço na stack para o 'i' e 'j') irmovl $10, %ebx ; %ebx = 10 rmmovl %ebx, -4(%ebp) ; -4(%ebp) = 10 (j = 10) addl %ebx, %ebx ; %ebx = %ebx + %ebx <=> %ebx = 10 + 10 = 20 addl %ebx, %ebx ; %ebx = %ebx + %ebx <=> %ebx = 20 + 20 = 40 rmmovl %ebx, -8(%ebp) ; -8(%ebp) = 40 (i = 40 <=> i = j*4) halt .pos 50 Stack: .long 0 Foi isto que disseste? EDIT: Penso que agora faz mais sentido, estava a esquecer-me de reservar espaço na stack (modificar o %esp). Link to comment Share on other sites More sharing options...
20_LESI Posted June 21, 2009 at 02:17 PM Author Report Share #273898 Posted June 21, 2009 at 02:17 PM Não vejo onde é que essa linha estaria mal, com as linhas irmovl 8, %ecx e subl %ecx, %esp estás a guardar espaço para o j e o ret, correcto? E de seguida usas o -4 para aceder ao ret e -8 para o j, acho que está bem... Já descobri o erro! O que eu estava a fazer mal era somente isto: rrmovl %ebp, %esp pois deveria ser: rrmovl %esp, %ebp Eu acho é que estas a fazer mal no p porque o p também vai ser uma variável local que recebe o valor quando f é chamado. Logo, acho que te falta reservar algum espaço na stack (dentro do stack frame de f) para o p. O que eu fazia, era remover o pushl %ebx do main e coloca-lo no f logo a seguir a inicialização da stack, acho que faz mais sentido porque o p é local. Não creio. Existe um espaço na stack frame de uma função para os parâmetros. Repara como ficou o código, já com as alterações finais: .pos 0 irmovl Stack, %esp rrmovl %esp, %ebp jmp main f: pushl %ebp # salva %ebp rrmovl %esp, %ebp # inicializa a stack frame da função f irmovl 1, %eax # ret = 1 pushl %eax # guarda o valor de ret na stack mrmovl 8(%ebp), %ecx # j = p (vai buscar o parâmetro p) pushl %ecx # guarda o valor de j na stack for1: irmovl 1, %edx rrmovl %ecx, %eax # salvaguarda o valor da variável j dentro do ciclo subl %edx, %ecx # j=j-1 jle fim_for1 mrmovl -4(%ebp), %edx # vai à stack buscar o valor da variável ret addl %edx, %eax # ret = j+ret rmmovl %eax, -4(%ebp) # guardar o valor da variável ret na stack jmp for1 fim_for1: rrmovl %ebp, %esp popl %ebp ret # o valor de ret já se encontra na variável a, logo podemos retornar main: irmovl 3, %ebx pushl %ebx call f halt .pos250 Stack: Funciona na perfeição! Voltando ao problema inicial a ver se percebi o que disseste, para remover as variáveis locais tenho de as meter na stack, será assim: .pos 0 irmovl Stack, %esp rrmovl %esp, %ebp main: irmovl $8, %ebx ; %ebx = 8 subl %ebx, %esp ; %esp = %esp - %ebx (guarda espaço na stack para o 'i' e 'j') irmovl $10, %ebx ; %ebx = 10 rmmovl %ebx, -4(%ebp) ; -4(%esi) = 10 (j = 10) addl %ebx, %ebx ; %ebx = %ebx + %ebx <=> %ebx = 10 + 10 = 20 addl %ebx, %ebx ; %ebx = %ebx + %ebx <=> %ebx = 20 + 20 = 40 rmmovl %ebx, -8(%ebp) ; 0(%esi) = 40 (i = 40 <=> i = j*4) halt .pos 50 Stack: .long 0 Foi isto que disseste? EDIT: Penso que agora faz mais sentido, estava a esquecer-me de reservar espaço na stack (modificar o %esp). Sim. Acho que isso está correcto. Mas fica mais simples com pushl's. Repara nas alterações que fiz ao meu código! NOTA: No ciclo do programa em C, em vez de um * deveria estar um + Link to comment Share on other sites More sharing options...
Guest id194 Posted June 21, 2009 at 02:32 PM Report Share #273899 Posted June 21, 2009 at 02:32 PM Tudo bem, funciona, mas a questão não é essa lol... Há muita coisa que pode funcionar e não ser boa prática. Repara que eu só estou a dizer para fazeres pushl %ebx dentro do f, mais nada. Tu ao chamares f(3) no main, o 3 "pertence" ao main, esse valor faz parte do main (irmovl 3, %ebx) e não do f, tu vais é passar esse valor para o f. Dentro do f, esse valor pode mudar mas no main tu queres que ele continue a ser 3, logo tu tens de fazer um pushl %ebx dentro do f para salvaguardar o 3 e no fim de tudo fazes um popl %ebx para restaurar esse 3 caso o valor do %ebx tenha sido mudado no f, que por acaso não foi. Mas como o %ebx é callee save, é boa prática fazeres o push e o pop dele. Isso está nos slides do prof, vai lá ver. No geral, nem se quer tinha lógica fazeres pushl/popl do %ebx, não o estás a mudar na rotina f e quando a função f fizer ret, o programa termina (halt). Mas é boa prática, e essa boa prática faz-se dentro do f, no caso do %ebx. Lê bem os slides na parte de "caller save" e "callee save". Quando ao outro problema... Com pushs ou com subl vai dar ao mesmo, desde que um gajo reserve espaço lol... Ok, vai dar ao mesmo no sentido de que reservamos espaço, mas óbvio que ao usar o pushl é mais rápido e mais simples (uma instrução ao contrário de duas irmovl/subl). Link to comment Share on other sites More sharing options...
20_LESI Posted June 21, 2009 at 03:12 PM Author Report Share #273904 Posted June 21, 2009 at 03:12 PM Tudo bem, funciona, mas a questão não é essa lol... Há muita coisa que pode funcionar e não ser boa prática. Repara que eu só estou a dizer para fazeres pushl %ebx dentro do f, mais nada. Tu ao chamares f(3) no main, o 3 "pertence" ao main, esse valor faz parte do main (irmovl 3, %ebx) e não do f, tu vais é passar esse valor para o f. Dentro do f, esse valor pode mudar mas no main tu queres que ele continue a ser 3, logo tu tens de fazer um pushl %ebx dentro do f para salvaguardar o 3 e no fim de tudo fazes um popl %ebx para restaurar esse 3 caso o valor do %ebx tenha sido mudado no f, que por acaso não foi. Mas como o %ebx é callee save, é boa prática fazeres o push e o pop dele. Isso está nos slides do prof, vai lá ver. No geral, nem se quer tinha lógica fazeres pushl/popl do %ebx, não o estás a mudar na rotina f e quando a função f fizer ret, o programa termina (halt). Mas é boa prática, e essa boa prática faz-se dentro do f, no caso do %ebx. Lê bem os slides na parte de "caller save" e "callee save". Já li isso bem, tal como algumas partes do CS:APP! O %ebx é um registo callee save, e no CS:APP diz o seguinte: Um procedimento P vai chamar um procedimento Q, e vai necessitar de um valor X antes e após a chamada de Q. Pode proceder de duas formas:A: Guardar o valor de X na sua própria Stack Frame antes de invocar Q. Após Q retornar, poderá aceder ao valor de X através da Stack B: Guardar o valor de X num registo callee save. Se Q ou qualquer outro procedimento invocado por Q tiver que usar este registo, o valor de X deverá ser guardado na sua Stack Frame e posteriormente restaurado, antes do retorno de Q Diz também que os processadores costumam optar pela solução B! Eu estou a utilizar a solução B, tu dizes-me para utilizar a solução A. Por aquilo que o jmf diz, realmente deveríamos optar pela solução A, mas farto de pushl's e popl's já eu estou! Vou optar pela solução B, e deixar um comentário (que vou levar na folha) para explicar o que fiz... É de mim, ou desde que começou esta conversa, tanto eu como tu já evoluímos bué em Y86? ? Link to comment Share on other sites More sharing options...
Guest id194 Posted June 21, 2009 at 03:42 PM Report Share #273906 Posted June 21, 2009 at 03:42 PM Não lol, eu estou a dizer para tu utilizares a B mesmo... Repara o %ebx é "callee save" que é o que tu estas a usar, logo, segundo que colocaste ai, se Q tiver que usar o %ebx, o valor tem de ser guardado na sua stack frame (na de Q) e posteriormente restaurado antes do retorno de Q, ou seja: Q: pushl %ebp rrmovl %esp, %ebp pushl %ebx ; guarda o valor de %ebx porque ele é callee save irmovl $5, %ebx ; muda o valor de %ebx (só para exemplo) popl %ebx ; restaura o valor do stack pointer para o %ebx ret Isto é o que a opção B diz, e isto não é o que tu estás a fazer... Tu estás a fazer A: main: irmovl 3, %ebx pushl %ebx call f Ou seja, tu estás a guardar o valor do %ebx na própria stack do main e não no stack frame do f. Isto é a opção A e não a B. Eu acho que depende um pouco da solução do problema... Por exemplo, se no main usasses o %eax, que é caller save (e não callee) só precisavas de fazer um pushl %eax no main caso o fosses o usar na função f (mesmo que não o usasses na função f, como diz os slides, é boa prática fazê-lo). Se fosse o %ebx que é callee (e não caller), tens de fazer o pushl %ebx dentro da stack frame do f e no fim popl %ebx. Resumindo: Se usas registos "caller save" e a função que invoca (main) outra função (f) precisa de manter esses registos, então tem de os guardar previamente na sua stack (main). Se usas registos "callee save", eles não podem ser alterados na função invocada (f), se precisam de ser alterados, têm de ser guardados na própria stack frame (f) e depois restaurados no fim. Penso que estou correcto e só estou a seguir o raciocínio dos slides... Link to comment Share on other sites More sharing options...
20_LESI Posted June 21, 2009 at 03:52 PM Author Report Share #273911 Posted June 21, 2009 at 03:52 PM Estás! Eu é que falei sem olhar bem para o código! Ou seja, isto aqui: main: irmovl 3, %ebx pushl %ebx call f Nem seria necessário pois o registo %ebx é callee save. Segundo o que tu dizes, é boa prática guardar o seu valor no início procedimento f, e restaurá-lo no fim. Certo? Link to comment Share on other sites More sharing options...
Guest id194 Posted June 21, 2009 at 03:59 PM Report Share #273913 Posted June 21, 2009 at 03:59 PM Se usares o %ebx, sim (ou outro registo qualquer que também seja callee save). Se usasses um registo caller save, ai sim, já fazias o pushl no main (tal como tens, mas para o respectivo registo) e no procedimento f n precisavas de guardar/restaurar. Ou seja, depende do registo que usares. Isto é o que diz os slides, diz que isto é boa prática, porque que realmente funciona assim ou porquê que se deve fazer assim, não faço a mínima 😕 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now