def apply_macros(macro_dictionary, program_string):
    """
    Apply macros to the source code.

    :param macro_dictionary: a dictionary of macros (e.g., {"UINT32_MAX": 4294967296, "SAVED_REG": "%r0"})
    :param program_string: assembly program
    :return: the program with macros substituted
    """

    # Sort the macros from longest to shortest to cover the case where macros are substrings of one another.
    macros = macro_dictionary.keys()
    macros = sorted(macros, key=lambda m: -len(m))

    # Replace all the macros with their values.
    for macro in macros:
        program_string = program_string.replace(macro, str(macro_dictionary[macro]))  # Allow for duck-typed macros.

    # Return the preprocessed program.
    return program_string