a * b % m equals a * b - (a * b / m) * m
Use floating point arithmetic to approximate a * b / m.  The approximation leaves a value small enough for normal 64 bit integer operations, for m up to 63 bits.
This method is limited by the significand of a double, which is usually 52 bits.
uint64_t mod_mul_52(uint64_t a, uint64_t b, uint64_t m) {
    uint64_t c = (double)a * b / m - 1;
    uint64_t d = a * b - c * m;
    return d % m;
}
This method is limited by the significand of a long double, which is usually 64 bits or larger.  The integer arithmetic is limited to 63 bits.
uint64_t mod_mul_63(uint64_t a, uint64_t b, uint64_t m) {
    uint64_t c = (long double)a * b / m - 1;
    uint64_t d = a * b - c * m;
    return d % m;
}
These methods require that a and b be less than m.  To handle arbitrary a and b, add these lines before c is computed.
a = a % m;
b = b % m;
In both methods, the final % operation could be made conditional.
return d >= m ? d % m : d;