// File: /workspace/github_c_makefile_star2_O2/gadget114514[P]fatfs-example/fatfs/source/ff.c
// Function: f_lseek
FRESULT f_lseek (
	FIL* fp,		/* Pointer to the file object */
	FSIZE_t ofs		/* File pointer from top of file */
)
{
	FRESULT res;
	FATFS *fs;
	DWORD clst, bcs, nsect;
	FSIZE_t ifptr;
#if FF_USE_FASTSEEK
	DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
#endif

	res = validate(&fp->obj, &fs);		/* Check validity of the file object */
	if (res == FR_OK) res = (FRESULT)fp->err;
#if FF_FS_EXFAT && !FF_FS_READONLY
	if (res == FR_OK && fs->fs_type == FS_EXFAT) {
		res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF);	/* Fill last fragment on the FAT if needed */
	}
#endif
	if (res != FR_OK) LEAVE_FF(fs, res);

#if FF_USE_FASTSEEK
	if (fp->cltbl) {	/* Fast seek */
		if (ofs == CREATE_LINKMAP) {	/* Create CLMT */
			tbl = fp->cltbl;
			tlen = *tbl++; ulen = 2;	/* Given table size and required table size */
			cl = fp->obj.sclust;		/* Origin of the chain */
			if (cl != 0) {
				do {
					/* Get a fragment */
					tcl = cl; ncl = 0; ulen += 2;	/* Top, length and used items */
					do {
						pcl = cl; ncl++;
						cl = get_fat(&fp->obj, cl);
						if (cl <= 1) ABORT(fs, FR_INT_ERR);
						if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
					} while (cl == pcl + 1);
					if (ulen <= tlen) {		/* Store the length and top of the fragment */
						*tbl++ = ncl; *tbl++ = tcl;
					}
				} while (cl < fs->n_fatent);	/* Repeat until end of chain */
			}
			*fp->cltbl = ulen;	/* Number of items used */
			if (ulen <= tlen) {
				*tbl = 0;		/* Terminate table */
			} else {
				res = FR_NOT_ENOUGH_CORE;	/* Given table size is smaller than required */
			}
		} else {						/* Fast seek */
			if (ofs > fp->obj.objsize) ofs = fp->obj.objsize;	/* Clip offset at the file size */
			fp->fptr = ofs;				/* Set file pointer */
			if (ofs > 0) {
				fp->clust = clmt_clust(fp, ofs - 1);
				dsc = clst2sect(fs, fp->clust);
				if (dsc == 0) ABORT(fs, FR_INT_ERR);
				dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1);
				if (fp->fptr % SS(fs) && dsc != fp->sect) {	/* Refill sector cache if needed */
#if !FF_FS_TINY
#if !FF_FS_READONLY
					if (fp->flag & FA_DIRTY) {		/* Write-back dirty sector cache */
						if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
						fp->flag &= (BYTE)~FA_DIRTY;
					}
#endif
					if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);	/* Load current sector */
#endif
					fp->sect = dsc;
				}
			}
		}
	} else
#endif

	/* Normal Seek */
	{
#if FF_FS_EXFAT
		if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF;	/* Clip at 4 GiB - 1 if at FATxx */
#endif
		if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) {	/* In read-only mode, clip offset with the file size */
			ofs = fp->obj.objsize;
		}
		ifptr = fp->fptr;
		fp->fptr = nsect = 0;
		if (ofs > 0) {
			bcs = (DWORD)fs->csize * SS(fs);	/* Cluster size (byte) */
			if (ifptr > 0 &&
				(ofs - 1) / bcs >= (ifptr - 1) / bcs) {	/* When seek to same or following cluster, */
				fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1);	/* start from the current cluster */
				ofs -= fp->fptr;
				clst = fp->clust;
			} else {									/* When seek to back cluster, */
				clst = fp->obj.sclust;					/* start from the first cluster */
#if !FF_FS_READONLY
				if (clst == 0) {						/* If no cluster chain, create a new chain */
					clst = create_chain(&fp->obj, 0);
					if (clst == 1) ABORT(fs, FR_INT_ERR);
					if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
					fp->obj.sclust = clst;
				}
#endif
				fp->clust = clst;
			}
			if (clst != 0) {
				while (ofs > bcs) {						/* Cluster following loop */
					ofs -= bcs; fp->fptr += bcs;
#if !FF_FS_READONLY
					if (fp->flag & FA_WRITE) {			/* Check if in write mode or not */
						if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) {	/* No FAT chain object needs correct objsize to generate FAT value */
							fp->obj.objsize = fp->fptr;
							fp->flag |= FA_MODIFIED;
						}
						clst = create_chain(&fp->obj, clst);	/* Follow chain with forceed stretch */
						if (clst == 0) {				/* Clip file size in case of disk full */
							ofs = 0; break;
						}
					} else
#endif
					{
						clst = get_fat(&fp->obj, clst);	/* Follow cluster chain if not in write mode */
					}
					if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
					if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);
					fp->clust = clst;
				}
				fp->fptr += ofs;
				if (ofs % SS(fs)) {
					nsect = clst2sect(fs, clst);	/* Current sector */
					if (nsect == 0) ABORT(fs, FR_INT_ERR);
					nsect += (DWORD)(ofs / SS(fs));
				}
			}
		}
		if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) {	/* Set file change flag if the file size is extended */
			fp->obj.objsize = fp->fptr;
			fp->flag |= FA_MODIFIED;
		}
		if (fp->fptr % SS(fs) && nsect != fp->sect) {	/* Fill sector cache if needed */
#if !FF_FS_TINY
#if !FF_FS_READONLY
			if (fp->flag & FA_DIRTY) {			/* Write-back dirty sector cache */
				if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
				fp->flag &= (BYTE)~FA_DIRTY;
			}
#endif
			if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);	/* Fill sector cache */
#endif
			fp->sect = nsect;
		}
	}

	LEAVE_FF(fs, res);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rsi, %r13
movq %rdi, %rbx
leaq -0x40(%rbp), %rsi
callq 0x228f
movl %eax, %r12d
testl %eax, %eax
jne 0x291b
movzbl 0x21(%rbx), %r12d
testl %r12d, %r12d
je 0x292d
movl %r12d, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x18(%rbx), %rax
cmpq %r13, %rax
jae 0x294f
testb $0x2, 0x20(%rbx)
je 0x2952
leaq 0x28(%rbx), %rax
movq %rax, -0x30(%rbp)
movq 0x28(%rbx), %rcx
andq $0x0, 0x28(%rbx)
jmp 0x296f
movq %r13, %rax
movq 0x28(%rbx), %rcx
andq $0x0, 0x28(%rbx)
testq %rax, %rax
je 0x2aa1
leaq 0x28(%rbx), %rdx
movq %rdx, -0x30(%rbp)
movq %rax, %r13
movq -0x40(%rbp), %rax
movq %rax, -0x38(%rbp)
movzwl 0xa(%rax), %r12d
shll $0x9, %r12d
testq %rcx, %rcx
je 0x29a1
leaq -0x1(%r13), %rax
xorl %edx, %edx
divq %r12
movq %rax, %rsi
decq %rcx
movq %rcx, %rax
xorl %edx, %edx
divq %r12
cmpq %rax, %rsi
jae 0x29b4
movq 0x10(%rbx), %rax
testq %rax, %rax
je 0x2aa9
movq %rax, 0x30(%rbx)
jmp 0x29c8
movq %r12, %rax
negq %rax
andq %rax, %rcx
movq %rcx, 0x28(%rbx)
subq %rcx, %r13
movq 0x30(%rbx), %rax
testq %rax, %rax
je 0x2a3d
movq %r13, %r14
movq -0x30(%rbp), %rcx
movq (%rcx), %r15
subq %r12, %r14
jbe 0x2ae0
addq %r12, %r15
movq %r15, 0x28(%rbx)
testb $0x2, 0x20(%rbx)
jne 0x29fa
movq %rbx, %rdi
movq %rax, %rsi
callq 0x1ed8
jmp 0x2a0e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2595
testq %rax, %rax
je 0x2ad4
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, %rax
je 0x2acc
cmpq $0x2, %rax
jb 0x2b16
movq -0x38(%rbp), %rcx
cmpq 0x20(%rcx), %rax
jae 0x2b16
movq %rax, 0x30(%rbx)
movq %r14, %r13
jmp 0x29d0
movq -0x30(%rbp), %rax
movq (%rax), %r15
xorl %r14d, %r14d
cmpq 0x18(%rbx), %r15
jbe 0x2a55
movq %r15, 0x18(%rbx)
orb $0x40, 0x20(%rbx)
xorl %r12d, %r12d
shlq $0x37, %r15
je 0x291b
movq 0x38(%rbx), %rdx
cmpq %rdx, %r14
je 0x291b
cmpb $0x0, 0x20(%rbx)
movq -0x40(%rbp), %r15
js 0x2b23
movzbl 0x1(%r15), %edi
leaq 0x50(%rbx), %rsi
pushq $0x1
popq %r12
movq %r14, %rdx
movl %r12d, %ecx
callq 0x12c4
testl %eax, %eax
jne 0x2b3c
movq %r14, 0x38(%rbx)
xorl %r12d, %r12d
jmp 0x291b
movq %rbx, %rdi
xorl %esi, %esi
callq 0x2595
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, %rax
je 0x2acc
cmpq $0x1, %rax
je 0x2b16
movq %rax, 0x10(%rbx)
jmp 0x29ae
movb $0x1, 0x21(%rbx)
pushq $0x1
jmp 0x2b1c
movq -0x30(%rbp), %rax
movq (%rax), %r15
xorl %eax, %eax
xorl %r13d, %r13d
addq %r13, %r15
movq -0x30(%rbp), %rcx
movq %r15, (%rcx)
testw $0x1ff, %r13w           # imm = 0x1FF
je 0x2a44
movq -0x38(%rbp), %rdi
movq %rax, %rsi
callq 0x201a
testq %rax, %rax
je 0x2b16
movq %rax, %r14
shrq $0x9, %r13
addq %r13, %r14
jmp 0x2a47
movb $0x2, 0x21(%rbx)
pushq $0x2
popq %r12
jmp 0x291b
movzbl 0x1(%r15), %edi
leaq 0x50(%rbx), %rsi
pushq $0x1
popq %r12
movl %r12d, %ecx
callq 0x131f
testl %eax, %eax
je 0x2b45
movb $0x1, 0x21(%rbx)
jmp 0x291b
andb $0x7f, 0x20(%rbx)
jmp 0x2a7d