【问题标题】:ASM/NASM - Return high low of a MUL in a type structASM/NASM - Return high low of a MUL in a type struct
【发布时间】:2022-12-02 10:12:11
【问题描述】:
global mymul
mymul:
    mov rax, rdi
    mul rsi
    ret

#include <stdio.h>

typedef struct {
        unsigned long long high;
            unsigned long long low;
} resmul;

void mymul(unsigned long long, unsigned long long, resmul *res);

int main() {
    resmul res;

    mymul(3, 6, &res);
    printf("mymul(3, 6); res.high=0x%llx, res.low=0x%llx\n", res.high, res.low);
    //mymul(3, 6); res.high=0x0, res.low=0x12
    return 0;
}

the goal is to multiply first arg with the second and send to result to the last arg first arg = RDI / second arg = RSI goal to send result high/low to typestruct

I dont understand why it gives 0 to both results RAX and RDX should be returned but i doesnt

【问题讨论】:

    标签: assembly x86-64 nasm calling-convention int128


    【解决方案1】:

    Your mymul function is declared from C as taking a pointer argument, where it should be storing the results in memory. But in fact it is leaving them in the rdx:rax registers and never storing anything in memory at all, ignoring the pointer completely.

    The third argument would be passed in the rdx register, which complicates things a little because mul overwrites it. So you have to do something like

    global mymul
    mymul:
        mov rcx, rdx  ; save argument
        mov rax, rdi
        mul rsi
        mov [rcx], rdx
        mov [rcx+8], rax
        ret
    

    【讨论】:

    • Oh thanks! But why do we add + and not 8, shouldnt we add 4 bytes ?
    • @1111B: unsigned long long is 64 bits which is 8 bytes. Your mymul function is multiplying two 64-bit inputs to produce a 128-bit output.
    【解决方案2】:

    You told the compiler your function returns void, so the caller isn't looking at RDX:RAX.

    Use a debugger and/or look at the asm in the caller; it will be loading its uninitialized local variable res from the stack, and that unwritten stack memory just happens to be zero.


    To properly declare a function returning in RDX:RAX for the x86-64 SysV calling convention, eitherreturn a struct, or return unsigned __int128 if you're using GNU extensions.

    #include <stdio.h>
    #include <stdint.h>
    
    typedef struct {
            uint64_t low;         // low first, the low half of RDX:RAX
            uint64_t high;
    } resmul;              // x86-64 System V will return this in RDX:RAX, like __int128
    
    resmul mymul(uint64_t, uint64_t);  // your function doesn't look for a pointer in RDX
    
    int main() {
        resmul res = mymul(3, 6);
        printf("mymul(3, 6); res.high=%#lx, res.low=%#lx
    ", res.high, res.low);
        //mymul(3, 6); res.high=0x0, res.low=0x12
        return 0;
    }
    

    Godbolt, also including GNU C implementations of your function that compile to the same asm:

    // compiles to the same asm
    resmul mymul(uint64_t a, uint64_t b){
        unsigned __int128 prod = a * (unsigned __int128)b;
        return (resmul){prod, prod>>64};
    }
    
    unsigned __int128 mulv2(uint64_t a, uint64_t b){
        return a * (unsigned __int128)b;
    }
    
    mymul(unsigned long, unsigned long):
            mov     rax, rdi
            mul     rsi
            ret
    mulv2(unsigned long, unsigned long):
            mov     rax, rdi
            mul     rsi
            ret
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-01
      • 2022-12-27
      • 2023-02-17
      • 1970-01-01
      • 2022-11-20
      • 2020-04-27
      • 1970-01-01
      • 2022-12-01
      相关资源
      最近更新 更多