Thread: Mixed Language: C and Asm

  1. #31
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    wow it worked, very cool Thanks!

    I don't get it. The book I am using used it, and some tutorials.
    It says it frees the stack by restoring it to its original value.


    The whole purpose of the pops is to bring esp down while moving the clobbered registers back to what they're supposed to be.
    do you mean the bring the esp up, as in esp+4 on every pop?

    If you fiddle with esp, now you're popping the old ebp into eax, the eip (i.e., where to return to from this function) into edi, probably the [11] byte of one of your strings (depending which one was loaded where) into esi, the [10] byte of that string into ebp [eep!] and then using the [9] byte of the string as the return address to jump to with ret. And that's not going to be pleasant.
    what? haha how does that happen by simply moving %ebp to %esp, crazy stuff!
    You ended that sentence with a preposition...Bastard!

  2. #32
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    What the book is (probably) doing is getting rid of its own stack variables, which you didn't have any thus making any attempt to do so misguided.

    When you do a pop, it looks at where esp is (since esp is the last/"top" thing on the stack). If you fiddle with esp and then start popping, you're going to pop from where esp thinks your stack is, not where it actually is.

  3. #33
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    but how can you tell that ebp would now be ebp and eip in edi and so on, that's really cool.

    How can i return an actual value from a function? They have been void so far. unfortunately the ebook didn't cover that.
    i would like to compare a strings. if they are equal return 0, else 1. but ret seems be for the return address in %eax, which i thought the eip dealt with
    You ended that sentence with a preposition...Bastard!

  4. #34
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Generally you're expected to place the return value in %eax before you go back. eip is just an instruction pointer -- it just says "when you go back, this is the next line of code that needs to run".

  5. #35
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    eip is the address that should be returned to, isn't it?
    what ret uses to return?
    if the return value is to be put into %eax, then popping %eax of the stack would overwrite the return val, which means i can't pop it off?
    Thanks a lot for your help.
    You ended that sentence with a preposition...Bastard!

  6. #36
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Eman View Post
    eip is the address that should be returned to, isn't it?
    what ret uses to return?
    if the return value is to be put into %eax, then popping %eax of the stack would overwrite the return val, which means i can't pop it off?
    Thanks a lot for your help.
    I ... that's true. What that means is that you should never push %eax on the stack in the first place. The whole point of pushing registers on the stack is so they can be restored later, so that the calling function doesn't lose data. Again, it's conventional as to which registers need to be restored and which don't. For instance, you've been using the c register and not restoring it; but most conventions specify that function calls can clobber the c register and get away with it. (Usually you can get away with using the d register too I understand.) But again: this is all convention, meaning that whatever the calling function and the called function agree on, works.

  7. #37
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    You can push eax onto the stack if you remember to pop it off before putting the return value in there, or if you fake the pop with stack pointer arithmetic, like "add %esp, $4", to bump the stack pointer up 4 bytes and skip over the value of eax you pushed. This sort of arithmetic is often done as a quick way to clean up the stack at the end of a function too, but you have to make sure you count your stack usage carefully.

    Since you pushed eax onto the stack at the start of cstring, you would want to pop it off near the end to keep your stack aligned, or add 4 to esp skip over the value you pushed on the stack. The more likely case of pushing eax onto the stack however, seems to me to be that the calling code had a value in eax it wanted to preserve, so before pushing on all the function parameters, it pushed eax to save the value during the function call. It would then do whatever it needs to with the return value that is in eax when the function is done, then pop the old eax off the stack for use.

    Here are a couple of interesting sites with some pretty good information on x86 registers and their usage, though neither really cover eax as a return value:
    x86 Registers
    The Art of Picking Intel Registers

  8. #38
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Hey!
    After an hour of sweating it out, I finally figured out how to do it. I didn't push or pop it at all, although i got some problem with it, that only the function and exit could write to it. Other labels couldn't write values to it :S

    The more likely case of pushing eax onto the stack however, seems to me to be that the calling code had a value in eax it wanted to preserve, so before pushing on all the function parameters, it pushed eax to save the value during the function call. It would then do whatever it needs to with the return value that is in eax when the function is done, then pop the old eax off the stack for use.
    I was the one that pushed eax to the stack. Since that didn't work, I just didn't do it again.
    So if i returned control back to main. How would I pop %eax, because I would be in the C code then.
    This is what I got so far. appears to be working
    Code:
    #include <stdio.h>
    
    int cmpString(char *s1, char *s2);
    
    int main()
    
    {
    
      char string1[]="Hello World" ;
    
     
    
      char string2[]="Hello World" ;
    
     
    
     
    
        if(!cmpString(string1,string2))
    
        {
    
          printf("The strings match!\n") ;
    
        }
    
        else
    
        {
    
            printf("The strings do not match!\n") ;
    
        }
    
     
    
      return 0 ;
    
    }
    
    /*c function to compare strings
    
    int cmpString(char *s1, char *s2)
    
    {
    
     
    
        while((*s1!='\0'))
    
        {
    
            if(!(*s1==*s2))
    
            {    
    
                       return 1;
    
            }
    
            s1++ ;s2++ ;
    
        }
    
            return 0;
    
    }
    
     */
    
    Assembler code to compare string. 
    
    .section .data
    
     
    
    .section .text
    
     
    
        .global cmpString
    
     
    
    cmpString:
    
     
    
        push %ebp
    
     
    
        movl %esp, %ebp
    
     
    
        pushl %esi #save contents of esi
    
     
    
        pushl %edi #save contents of edi
    
        pushl  %ebx #save contents of ebx
    
     
    
        movl 12(%ebp), %esi #point to s2
    
     
    
        movl 8(%ebp), %edi#point to string1
    
     
    
    cmpLoop:
    
     
    
     
    
        cmpb $0, (%esi)
    
        je exit
    
        movb (%esi),%bl
    
     
    
        cmpb %bl, (%edi)
    
        movl $1, %eax
    
        jnz exit
    
     
    
        incl %esi
    
        incl %edi
    
        movl $0, %eax
    
        jmp cmpLoop
    
     
    
     
    
    exit:
    
     
    
        popl %ebx
    
        popl %edi
    
        popl %esi
    
        popl %ebp
    
     
    
        ret
    
        .end
    You ended that sentence with a preposition...Bastard!

  9. #39
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    You don't want to pop eax. If you mean "what is main going to do with %eax", then it looks like main is going to do jump-if-zero based on the value of %eax (it would probably have to do a cmp first I would guess). If you had done some_variable=cmpString(), it would have mov'd %eax to the appropriate location in memory. And so on. The registers are not the same as the stack, and the registers are not on the stack, so trying to pop them doesn't really make sense.

    If you had written the calling code in assembler, then yes: if you had something in eax that you wanted, you would have to put it somewhere (you could push it on the stack, or you could write it to memory, or whatever). But what you do with it is on the caller -- the called function has no idea about any of that and can't worry about it in any way, shape, or form.

  10. #40
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    The cardinal rule is that, whatever you do to the stack and registers upon entering the function, you do the reverse upon leaving.

    You wouldn't pop eax in any explicit fashion since you're writing C code. Some compilers support in-line assembly, but that's a non-standard feature. The compiler may do something like this automatically to your C code under certain circumstances. Also, if you wrote an assembly function that called another, you may need to write such code.

  11. #41
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    By the way, your code doesn't actually work, at least not quite. What happens if string1 is "Hello World" and string2 is "Hello"?

  12. #42
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    oh yeah i see what you mean. I forgot to check if they were the same length .

    When i push registers into the stack. They are saved below the ebp, and themselves aren't they? That is why i have to pop them off in reverse.
    You ended that sentence with a preposition...Bastard!

  13. #43
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by Eman View Post
    oh yeah i see what you mean. I forgot to check if they were the same length .
    Don't check if they're the same length. You can write your code such that it fails if it gets a null in one string before the other one, even if they match up to that point.
    When i push registers into the stack. They are saved below the ebp, and themselves aren't they? That is why i have to pop them off in reverse.
    I'm not sure what you mean by "below the ebp, and themselves", but since you are the one in control of the pushing (in your function), they will be pushed on the stack whenever you say so. You could do this before pushing the ebp, but that would violate the convention, and is not recommended. Since you push the ebp first in your example, the old ebp goes on the stack, then the stack pointer is moved down 4 bytes, then you push the other registers, so they will be below the ebp, but nothing can be below itself.

  14. #44
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    why, is checking the same length bad. I could just the strlen, before I call the function. could maybe reduce overhead?
    Below each other i mean.
    push %ebp,%edi, %esi, %eax:
    ebp
    edi
    esi
    eax //then if i have locals
    2
    3
    4
    ?
    although reading the first local won't be
    ebp-4
    it would be ebp-16..
    So, I am wondering when you push registers, is that what happens? ( in this scenario)
    You ended that sentence with a preposition...Bastard!

  15. #45
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Eman View Post
    why, is checking the same length bad. I could just the strlen, before I call the function. could maybe reduce overhead?
    That would increase overhead, not reduce it. One: you'd need to store the lengths somewhere (which is literal overhead). Two: You'd have to walk each string twice (once to find the length, and then once more to compare) (which is not literal overhead, but just extra work).

    Quote Originally Posted by Eman View Post
    Below each other i mean.
    push %ebp,%edi, %esi, %eax:
    ebp
    edi
    esi
    eax //then if i have locals
    2
    3
    4
    ?
    although reading the first local won't be
    ebp-4
    it would be ebp-16..
    So, I am wondering when you push registers, is that what happens? ( in this scenario)
    If you push registers, then yes those values go on the stack at that appropriate place. You can do it before or after locals, it doesn't make a difference (as long as you get them off in the right order). (I believe it's customary for the registers to go first, though, as you have it.)

Popular pages Recent additions subscribe to a feed