definitions in the included header file:
Code:
/* Some macros used for patching. */
#define JAL(addr) (0x0c000000|(0x3ffffff&((addr)>>2)))
#define GETJADDR(addr) ((addr&0x03FFFFFF)<<2)
/* Structures */
struct EE_ELF_patch_data{
u32 mode; /* How the patch should be applied. */
u32 src[4]; /* Offset (Only the 1st element is used, the other 3 are ignored)/sample of the original data that needs to be patched, and is to be search for. */
u32 mask[4]; /* Source pattern Mask (Optional; If unneeded, just fill it with 0xFF bytes). */
u32 patchData[4];
};
Main code:
Code:
static int (*pCdRead)(u32 lsn, u32 nSectors, void *buffer, u32 *mode);
static int delayed_cdRead(u32 lsn, u32 nSectors, void *buffer, u32 *mode);
/*----------------------------------------------------------------------------------------*/
/* Patch an ELF that has been loaded into memory. */
/*----------------------------------------------------------------------------------------*/
inline void patch_ELF(void *buffer, struct EE_ELF_patch_data *patch){
u32 *ptr, i;
DEBUG_PRINTF("PS2ESDL_EE_CORE: Patching ELF. Start offset: %p. Mode: 0x%02x.\n", buffer, patch->mode);
/* patchData[0] -> Offset relative to the current offset to patch. */
DEBUG_PRINTF("PS2ESDL_EE_CORE: Applying delayed read patch.\n");
ptr=scan_pattern(patch->src, patch->mask, (void *)0x000D0000, (void *)0x02000000);
if(ptr!=NULL){
DEBUG_PRINTF("PS2ESDL_EE_CORE: Patching index 0x%04x relative to %p.\n", patch->patchData[0], ptr);
pCdRead=(void *)GETJADDR(ptr[patch->patchData[0]]);
ptr[patch->patchData[0]]=JAL((u32)&delayed_cdRead);
}
else DEBUG_PRINTF("PS2ESDL_EE_CORE: Warning! Error looking for the section to patch.\n");
DEBUG_PRINTF("PS2ESDL_EE_CORE: Completed patching operation.\n");
}
static void *scan_pattern(u32 *pattern, u32 *mask, void *start, void *end){
u32 *ptr;
for(ptr=start; ptr<(u32 *)end; ptr++){
if(
((ptr[0]&mask[0])==pattern[0])&&
((ptr[1]&mask[1])==pattern[1])&&
((ptr[2]&mask[2])==pattern[2])&&
((ptr[3]&mask[3])==pattern[3])
){
DEBUG_PRINTF("PS2ESDL_EE_CORE: Pattern found at %p.\n", ptr);
return((void *)ptr);
}
}
return NULL;
}
static int delayed_cdRead(u32 lsn, u32 nSectors, void *buffer, u32 *mode)
{
int result;
u32 i;
result=pCdRead(lsn, nSectors, buffer, mode);
for(i=0; i<0x0100000; i++) __asm("\tnop\n\tnop\n\tnop\n\tnop\n");
return(result);
}
The code searches EE RAM for a jump to sceCdRead(), and replaces the jump to the original sceCdRead to a function that causes a delay before jumping back to the original sceCdRead function.
If you plan to overwrite the original sceGSSyncVCallback() function with another function or need to replace multiple jumps to sceGSSyncVCallback(), then you might need to make some additional modifications (Like adding a loop).
But if you need to achieve the latter, I could probably add in some more code for you (Since it was part of the engine too, but of a different part of the engine).
This was what I did in 5 minutes, since I don't think that the other parts of the patch engine will be of use to you. 
Feel free to ask questions if the code seems complicated.
After all, I'm bad at explaining things in an easy way to others.