How could I generate and execute machine code at runtime?

前端 未结 3 1287
夕颜
夕颜 2021-02-02 04:37

The closest I have gotten to assembly is building my own Java Class library which loads class files and allows you to create, compile, and decompile classes. While endeavoring t

3条回答
  •  迷失自我
    2021-02-02 05:12

    In the comments I gave you a link to a file explaining things thoroughly.

    Most Assembly languages have a subroutine (the assembly word for function as far as your googling is concerned) implementation as two commands call and ret - maybe something similar.

    The implementation is nearly the same as a jump, excepts call stores in the stack the address of the next command, and ret pops it - that's why it's very important to maintain a balanced stack in the subroutine. Since you don't want to mess with registers which may contain important stuff/are limited, this is where you keep all your local variables, and hence balancing is an issue. You could of course do this yourself with jump and some pushing and popping.

    As far as "arguments" are concerned, a simple method is using registers. This is a problem if you need to pass more arguments than there are registers. A more robust method is pushing the arguments before the call. This is what many real 32-bit calling-conventions do. An example from the link I provided for a subroutine adding 3 numbers:

    # Save old EBP
    pushl %ebp
    # Change EBP
    movl %esp, %ebp
    # Save caller-save registers if necessary
    pushl %ebx
    pushl %esi
    pushl %edi
    # Allocate space for local variable
    subl $4, %esp
    # Perform the addition
    movl 8(%ebp), %eax
    addl 12(%ebp), %eax
    addl 16(%ebp), %eax
    movl %eax, -16(%ebp)
    # Copy the return value to EAX
    movl -16(%ebp), %eax
    # Restore callee-save registers if necessary
    movl -12(%ebp), %edi
    movl -8(%ebp), %esi
    movl -4(%ebp), %ebx
    # Restore ESP
    movl %ebp, %esp
    # Restore EBP
    popl %ebp
    # Return to calling
    ret
    

    Calling the subroutine:

    # Save caller-save registers if necessary
    pushl %eax
    pushl %ecx
    pushl %edx
    # Push parameters
    pushl $5
    pushl $4
    pushl $3
    # Call add3
    call add3
    # Pop parameters
    addl %12, %esp
    # Save return value
    movl %eax, wherever
    # Restore caller-save registers if necessary
    popl %edx
    popl %ecx
    popl %eax
    # Proceed!
    

    As you can see you need more work here then high languages. The pdf contains a detailed explanation includes how the stack works, but note that:

    1. You need to define how to handler register usage. In this example both the caller and the subroutine save the registers, just in case - you can of course simplify.
    2. Arguments and local variables are addressed relative to the stack pointer, locals positive, arguments negative.
    3. If this is a small thing you're making for yourself you can skip all this stack playing and just set aside registers for argument and return value transferring, maybe to practice before you go to more advance stuff.

提交回复
热议问题