diff options
-rw-r--r-- | Makefile | 7 | ||||
-rwxr-xr-x | include/assert.h | 43 | ||||
-rw-r--r-- | include/config.h | 16 | ||||
-rw-r--r-- | include/global.h | 1 | ||||
-rw-r--r-- | ld_script.txt | 87 | ||||
-rw-r--r-- | src/engine/main.c | 7 | ||||
-rw-r--r-- | src/libs/libc.c | 143 | ||||
-rwxr-xr-x | src/libs/libisagbprn.c | 151 | ||||
-rw-r--r-- | sym_bss.txt | 37 |
9 files changed, 346 insertions, 146 deletions
@@ -15,6 +15,8 @@ OBJCOPY := $(DEVKITARM)/bin/arm-none-eabi-objcopy LIBGCC := tools/agbcc/lib/libgcc.a +LIBC := tools/agbcc/lib/libc.a + SHA1 := sha1sum -c GFX := tools/gbagfx/gbagfx @@ -103,6 +105,9 @@ sound/songs/%.s: sound/songs/%.mid %src/libs/m4a_2.o: CC1 := tools/agbcc/bin/old_agbcc %src/libs/m4a_4.o: CC1 := tools/agbcc/bin/old_agbcc +%src/libs/libisagbprn.o: CC1 := tools/agbcc/bin/old_agbcc +%src/libs/libisagbprn.o: CFLAGS := -mthumb-interwork + $(SONG_OBJS): %.o: %.s $(AS) $(ASFLAGS) -I sound -o $@ $< @@ -161,7 +166,7 @@ build/$1/ld_script.ld: ld_script.txt build/$1/sym_bss.ld build/$1/sym_common.ld cd build/$1 && sed -f ../../ld_script.sed ../../ld_script.txt | sed "s#tools/#../../tools/#g" | sed "s#sound/#../../sound/#g" >ld_script.ld poke$1.elf: build/$1/ld_script.ld $$($1_OBJS) - cd build/$1 && $$(LD) -T ld_script.ld -Map ../../poke$1.map -o ../../$$@ $$($1_OBJS_REL) ../../$$(LIBGCC) + cd build/$1 && $$(LD) -T ld_script.ld -Map ../../poke$1.map -o ../../$$@ $$($1_OBJS_REL) ../../$$(LIBGCC) ../../$$(LIBC) poke$1.gba: %.gba: %.elf $$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $$< $$@ diff --git a/include/assert.h b/include/assert.h new file mode 100755 index 000000000..7a5e727e2 --- /dev/null +++ b/include/assert.h @@ -0,0 +1,43 @@ +#ifndef GUARD_GBASDKASSERT_H +#define GUARD_GBASDKASSERT_H + +// this header is based on the +// GBA SDK IsAgbAssert.h. + +#ifdef NOAGBPRN + #define AGBPrintInit() + #define AGBPutc(pBuf) + #define AGBPrint(pBuf) + #define AGBPrintf(...) + #define AGBPrintFlush1Block() + #define AGBPrintFlush() + #define AGBAssert(pFile, nLine, pExpression, nStopProgram) +#else + // without NOAGBPRN defined, this enables asserts for usage + // on a standard GBA debugger unit or in emulators that + // support it. + void AGBPrintInit(void); + void AGBPutc(const char pBuf); + void AGBPrint(const char *pBuf); + void AGBPrintf(const char *pBuf, ...); + void AGBPrintFlush1Block(void); + void AGBPrintFlush(void); + void AGBAssert(const char *pFile, int nLine, const char *pExpression, int nStopProgram); +#endif + +// when using AGB_WARNING, be sure to flush after as AGBAssert does not flush the string to console +// immediately after usage. +#ifdef NOAGBPRN + #define AGB_ASSERT(expression) +#else + #define AGB_ASSERT(expression) (expression) ? ((void *)0) : AGBAssert(__FILE__, __LINE__, #expression, 1); +#endif + +#ifdef NOAGBPRN + #define AGB_WARNING(expression) +#else + #define AGB_WARNING(expression) (expression) ? ((void *)0) : AGBAssert(__FILE__, __LINE__, #expression, 0); +#endif + + +#endif diff --git a/include/config.h b/include/config.h index 6a77c4c74..d9ed70a7c 100644 --- a/include/config.h +++ b/include/config.h @@ -1,6 +1,22 @@ #ifndef GUARD_CONFIG_H #define GUARD_CONFIG_H +// In the Generation 3 games, Asserts were used in various debug builds. +// Ruby/Sapphire and Emerald do not have these asserts while Fire Red +// still has them in the ROM. This is because the developers forgot +// to define NOAGBPRN before release, which is actually supposed to be +// NDEBUG, however this has been changed as Ruby's actual debug build +// does not use the AGBPrint features. + +// To note, Ruby/Sapphire likely did not use AGBPrint. This is because +// the german debug ROM of Ruby did not have any uses of AGBPrint and +// the assert commands but instead a "crash" screen. This config exists +// for convenience for the user of pokeruby and NOT because it is +// authoritative. These additions are for user convenience based on +// officially recommended SDK practices for debugging and is therefore +// still in part authoritative. +#define NOAGBPRN + #ifndef REVISION #define REVISION 0 #endif diff --git a/include/global.h b/include/global.h index a4e71852c..359344500 100644 --- a/include/global.h +++ b/include/global.h @@ -3,6 +3,7 @@ #include "gba/gba.h" #include "config.h" +#include "assert.h" // IDE support #ifdef __APPLE__ diff --git a/ld_script.txt b/ld_script.txt index 07334bd2c..3e8f45121 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -11,6 +11,44 @@ SECTIONS { { <EWRAM> + tools/agbcc/lib/libc.a:memcpy.o(.data); + tools/agbcc/lib/libc.a:memset.o(.data); + tools/agbcc/lib/libc.a:strcmp.o(.data); + tools/agbcc/lib/libc.a:strcpy.o(.data); + tools/agbcc/lib/libc.a:impure.o(.data); + tools/agbcc/lib/libc.a:vsprintf.o(.data); + tools/agbcc/lib/libc.a:vfprintf.o(.data); + tools/agbcc/lib/libc.a:wsetup.o(.data); + tools/agbcc/lib/libc.a:dtoa.o(.data); + tools/agbcc/lib/libc.a:fflush.o(.data); + tools/agbcc/lib/libc.a:findfp.o(.data); + tools/agbcc/lib/libc.a:freer.o(.data); + tools/agbcc/lib/libc.a:mtrim.o(.data); + tools/agbcc/lib/libc.a:fvwrite.o(.data); + tools/agbcc/lib/libc.a:fwalk.o(.data); + tools/agbcc/lib/libc.a:locale.o(.data); + tools/agbcc/lib/libc.a:makebuf.o(.data); + tools/agbcc/lib/libc.a:mallocr.o(.data); + tools/agbcc/lib/libc.a:mbtowc_r.o(.data); + tools/agbcc/lib/libc.a:memchr.o(.data); + tools/agbcc/lib/libc.a:memmove.o(.data); + tools/agbcc/lib/libc.a:mlock.o(.data); + tools/agbcc/lib/libc.a:mprec.o(.data); + tools/agbcc/lib/libc.a:s_isinf.o(.data); + tools/agbcc/lib/libc.a:s_isnan.o(.data); + tools/agbcc/lib/libc.a:sbrkr.o(.data); + tools/agbcc/lib/libc.a:stdio.o(.data); + tools/agbcc/lib/libc.a:strlen.o(.data); + tools/agbcc/lib/libc.a:syscalls.o(.data); + tools/agbcc/lib/libc.a:writer.o(.data); + tools/agbcc/lib/libc.a:callocr.o(.data); + tools/agbcc/lib/libc.a:closer.o(.data); + tools/agbcc/lib/libc.a:errno.o(.data); + tools/agbcc/lib/libc.a:fstatr.o(.data); + tools/agbcc/lib/libc.a:libcfunc.o(.data); + tools/agbcc/lib/libc.a:lseekr.o(.data); + tools/agbcc/lib/libc.a:readr.o(.data); + . = 0x40000; } @@ -24,10 +62,12 @@ SECTIONS { /* .bss.code starts at 0x3000F60 */ src/libs/m4a_2.o(.bss.code); + tools/agbcc/lib/libc.a:syscalls.o(.bss); /* COMMON starts at 0x3001760 */ <COMMON> - + unk_code_ram = .; + tools/agbcc/lib/libc.a:sbrkr.o(COMMON); . = 0x8000; } @@ -36,6 +76,7 @@ SECTIONS { .text : ALIGN(4) { + unk_code = .; asm/crt0.o(.text); src/engine/main.o(.text); src/engine/sprite.o(.text); @@ -390,6 +431,7 @@ SECTIONS { src/debug/unknown_debug_menu.o(.text); src/engine/name_string_util.o(.text); src/engine/menu_cursor.o(.text); + unk_code_end = .; } =0 script_data : @@ -433,9 +475,46 @@ SECTIONS { tools/agbcc/lib/libgcc.a:fp-bit.o(.text); tools/agbcc/lib/libgcc.a:_lshrdi3.o(.text); tools/agbcc/lib/libgcc.a:_negdi2.o(.text); - src/libs/libc.o(.text); + tools/agbcc/lib/libc.a:memcpy.o(.text); + tools/agbcc/lib/libc.a:memset.o(.text); + tools/agbcc/lib/libc.a:strcmp.o(.text); + tools/agbcc/lib/libc.a:vfprintf.o(.text); + tools/agbcc/lib/libc.a:vsprintf.o(.text); + tools/agbcc/lib/libc.a:fvwrite.o(.text); + tools/agbcc/lib/libc.a:locale.o(.text); + tools/agbcc/lib/libc.a:findfp.o(.text); + tools/agbcc/lib/libc.a:fflush.o(.text); + tools/agbcc/lib/libc.a:wsetup.o(.text); + tools/agbcc/lib/libc.a:mbtowc_r.o(.text); + tools/agbcc/lib/libc.a:s_isinf.o(.text); + tools/agbcc/lib/libc.a:s_isnan.o(.text); + tools/agbcc/lib/libc.a:memchr.o(.text); + tools/agbcc/lib/libc.a:strlen.o(.text); + tools/agbcc/lib/libc.a:dtoa.o(.text); + tools/agbcc/lib/libc.a:memmove.o(.text); + tools/agbcc/lib/libc.a:stdio.o(.text); + tools/agbcc/lib/libc.a:mprec.o(.text); + tools/agbcc/lib/libc.a:mallocr.o(.text); + tools/agbcc/lib/libc.a:fwalk.o(.text); + tools/agbcc/lib/libc.a:freer.o(.text); + tools/agbcc/lib/libc.a:makebuf.o(.text); + tools/agbcc/lib/libc.a:readr.o(.text); + tools/agbcc/lib/libc.a:writer.o(.text); + tools/agbcc/lib/libc.a:lseekr.o(.text); + tools/agbcc/lib/libc.a:closer.o(.text); + tools/agbcc/lib/libc.a:callocr.o(.text); + tools/agbcc/lib/libc.a:sbrkr.o(.text); + tools/agbcc/lib/libc.a:mlock.o(.text); + tools/agbcc/lib/libc.a:fstatr.o(.text); + tools/agbcc/lib/libc.a:libcfunc.o(.text); + tools/agbcc/lib/libc.a:syscalls.o(.text); + tools/agbcc/lib/libc.a:errno.o(.text); + src/libs/libisagbprn.o(.text); } =0 + unk_code_ram_end = unk_code_ram + (unk_code_end - unk_code); + end = unk_code_ram_end; + .rodata : ALIGN(4) { @@ -1038,6 +1117,10 @@ SECTIONS { src/libs/agb_flash_le.o(.rodata); src/libs/siirtc.o(.rodata); tools/agbcc/lib/libgcc.a:_udivdi3.o(.rodata); + tools/agbcc/lib/libc.a(.rodata); + tools/agbcc/lib/libc.a(.data); + tools/agbcc/lib/libc.a:syscalls.o(.rodata); + src/libs/libisagbprn.o(.rodata); } =0 . = 0x8D00000; diff --git a/src/engine/main.c b/src/engine/main.c index 82a5fffb4..11c540d07 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -98,6 +98,13 @@ void AgbMain() gSoftResetDisabled = FALSE; +// In Fire Red, AGBPrintInit is called at this spot. For user convenience, I +// opt to initialize the print area here. It is up to the user where they choose +// to print stuff from, as anything else declared is NOT authoritative. +#ifndef NOAGBPRN + AGBPrintInit(); +#endif + if (gFlashMemoryPresent != TRUE) SetMainCallback2(NULL); diff --git a/src/libs/libc.c b/src/libs/libc.c deleted file mode 100644 index 920673e3e..000000000 --- a/src/libs/libc.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "global.h" -#include <stddef.h> - -#define LBLOCKSIZE (sizeof(long)) - -// Nonzero if (long)X contains a NULL byte. -#define CONTAINSNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) - -// Nonzero if X is not aligned on a "long" boundary. -#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) - -void *memcpy(void *dst0, const void *src0, size_t len0) -{ - char *dst = dst0; - const char *src = src0; - long *aligned_dst; - const long *aligned_src; - unsigned int len = len0; - - // If the size is small, or either src or dst is unaligned, - // then go to the byte copy loop. This should be rare. - if (len >= 16 && !(UNALIGNED(src) | UNALIGNED(dst))) - { - aligned_dst = (long *)dst; - aligned_src = (long *)src; - - // Copy 4X long words at a time if possible. - while (len >= 16) - { - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - len -= 16; - } - - // Copy one long word at a time if possible - while (len >= 4) - { - *aligned_dst++ = *aligned_src++; - len -= 4; - } - - dst = (char *)aligned_dst; - src = (char *)aligned_src; - } - - // Pick up any remaining bytes with a byte copier. - while (len--) - *dst++ = *src++; - - return dst0; -} - -void *memset(void *m, int c, size_t n) -{ - char *s = (char *)m; - int count, i; - unsigned long buffer; - unsigned long *aligned_addr; - unsigned char *unaligned_addr; - - // If the size is small or m is unaligned, - // then go to the byte copy loop. This should be rare. - if (n >= LBLOCKSIZE && !UNALIGNED(m)) - { - // We know that n is large and m is word-aligned. - aligned_addr = (unsigned long *)m; - - // Store C into each char sized location in buffer so that - // we can set large blocks quickly. - c &= 0xFF; - if (LBLOCKSIZE == 4) - { - buffer = (c << 8) | c; - buffer |= (buffer << 16); - } - else - { - buffer = 0; - for (i = 0; i < LBLOCKSIZE; i++) - buffer = (buffer << 8) | c; - } - - while (n >= LBLOCKSIZE * 4) - { - *aligned_addr++ = buffer; - *aligned_addr++ = buffer; - *aligned_addr++ = buffer; - *aligned_addr++ = buffer; - n -= LBLOCKSIZE * 4; - } - while (n >= LBLOCKSIZE) - { - *aligned_addr++ = buffer; - n -= LBLOCKSIZE; - } - - s = (char *)aligned_addr; - } - - // Pick up the remainder with a bytewise loop. - while (n--) - *s++ = (char)c; - - return m; -} - -int strcmp(const char *s1, const char *s2) -{ - unsigned long *a1; - unsigned long *a2; - - // If s1 or s2 are unaligned, then skip this and compare bytes. - if (!(UNALIGNED(s1) | UNALIGNED(s2))) - { - // Compare them a word at a time. - a1 = (unsigned long *)s1; - a2 = (unsigned long *)s2; - while (*a1 == *a2) - { - // If *a1 == *a2, and we find a null in *a1, - // then the strings must be equal, so return zero. - if (CONTAINSNULL(*a1)) - return 0; - - a1++; - a2++; - } - - s1 = (char *)a1; - s2 = (char *)a2; - } - - // Check the remaining few bytes. - while (*s1 != '\0' && *s1 == *s2) - { - s1++; - s2++; - } - - return (*(unsigned char *) s1) - (*(unsigned char *) s2); -} diff --git a/src/libs/libisagbprn.c b/src/libs/libisagbprn.c new file mode 100755 index 000000000..64ccb6351 --- /dev/null +++ b/src/libs/libisagbprn.c @@ -0,0 +1,151 @@ +#include <stdarg.h> +#include <stdio.h> +#include "gba/gba.h" +#include "config.h" + +#define AGB_PRINT_FLUSH_ADDR 0x9FE209D +#define AGB_PRINT_STRUCT_ADDR 0x9FE20F8 +#define AGB_PRINT_PROTECT_ADDR 0x9FE2FFE +#define WSCNT_DATA (WAITCNT_PHI_OUT_16MHZ | WAITCNT_WS0_S_2 | WAITCNT_WS0_N_4) + +struct AGBPrintStruct +{ + u16 m_nRequest; + u16 m_nBank; + u16 m_nGet; + u16 m_nPut; +}; + +typedef void (*LPFN_PRINT_FLUSH)(void); + +#ifndef NOAGBPRN +void AGBPrintFlush1Block(void); + +void AGBPrintInit(void) +{ + volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + u16 *pWSCNT = (u16 *)REG_ADDR_WAITCNT; + u16 *pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; + u16 nOldWSCNT = *pWSCNT; + *pWSCNT = WSCNT_DATA; + *pProtect = 0x20; + pPrint->m_nRequest = pPrint->m_nGet = pPrint->m_nPut = 0; + pPrint->m_nBank = 0xFD; + *pProtect = 0; + *pWSCNT = nOldWSCNT; +} + +static void AGBPutcInternal(const char cChr) +{ + volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + u16 *pPrintBuf = (u16 *)(0x8000000 + (pPrint->m_nBank << 16)); + u16 *pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; + u16 nData = pPrintBuf[pPrint->m_nPut / 2]; + *pProtect = 0x20; + nData = (pPrint->m_nPut & 1) ? (nData & 0xFF) | (cChr << 8) : (nData & 0xFF00) | cChr; + pPrintBuf[pPrint->m_nPut / 2] = nData; + pPrint->m_nPut++; + *pProtect = 0; +} + +void AGBPutc(const char cChr) +{ + u16 *pWSCNT = (u16 *)REG_ADDR_WAITCNT; + u16 nOldWSCNT = *pWSCNT; + volatile struct AGBPrintStruct *pPrint; + *pWSCNT = WSCNT_DATA; + AGBPutcInternal(cChr); + *pWSCNT = nOldWSCNT; + pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + if (pPrint->m_nPut == ((pPrint->m_nGet - 1) & 0xFFFF)) + AGBPrintFlush1Block(); +} + +void AGBPrint(const char *pBuf) +{ + volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + u16 *pWSCNT = (u16 *)REG_ADDR_WAITCNT; + u16 nOldWSCNT = *pWSCNT; + *pWSCNT = WSCNT_DATA; + while (*pBuf) + { + AGBPutc(*pBuf); + pBuf++; + } + *pWSCNT = nOldWSCNT; +} + +void AGBPrintf(const char *pBuf, ...) +{ + char bufPrint[0x100]; + va_list vArgv; + va_start(vArgv, pBuf); + vsprintf(bufPrint, pBuf, vArgv); + va_end(vArgv); + AGBPrint(bufPrint); +} + +static void AGBPrintTransferDataInternal(u32 bAllData) +{ + LPFN_PRINT_FLUSH lpfnFuncFlush; + u16 *pIME; + u16 nIME; + u16 *pWSCNT; + u16 nOldWSCNT; + u16 *pProtect; + volatile struct AGBPrintStruct *pPrint; + + pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR; + pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR; + lpfnFuncFlush = (LPFN_PRINT_FLUSH)AGB_PRINT_FLUSH_ADDR; + pIME = (u16 *)REG_ADDR_IME; + nIME = *pIME; + pWSCNT = (u16 *)REG_ADDR_WAITCNT; + nOldWSCNT = *pWSCNT; + *pIME = nIME & ~1; + *pWSCNT = WSCNT_DATA; + + if (bAllData) + { + while (pPrint->m_nPut != pPrint->m_nGet) + { + *pProtect = 0x20; + lpfnFuncFlush(); + *pProtect = 0; + } + } + else if (pPrint->m_nPut != pPrint->m_nGet) + { + *pProtect = 0x20; + lpfnFuncFlush(); + *pProtect = 0; + } + + *pWSCNT = nOldWSCNT; + *pIME = nIME; +} + +void AGBPrintFlush1Block(void) +{ + AGBPrintTransferDataInternal(FALSE); +} + +void AGBPrintFlush(void) +{ + AGBPrintTransferDataInternal(TRUE); +} + +void AGBAssert(const char *pFile, int nLine, const char *pExpression, int nStopProgram) +{ + if (nStopProgram) + { + AGBPrintf("ASSERTION FAILED FILE=[%s] LINE=[%d] EXP=[%s] \n", pFile, nLine, pExpression); + AGBPrintFlush(); + asm(".hword 0xEFFF"); + } + else + { + AGBPrintf("WARING FILE=[%s] LINE=[%d] EXP=[%s] \n", pFile, nLine, pExpression); + } +} +#endif diff --git a/sym_bss.txt b/sym_bss.txt index 6587c2c39..ff3b3de01 100644 --- a/sym_bss.txt +++ b/sym_bss.txt @@ -39,3 +39,40 @@ .include "src/libs/siirtc.o" .include "tools/agbcc/lib/libgcc.a:dp-bit.o" .include "tools/agbcc/lib/libgcc.a:fp-bit.o" + .include "tools/agbcc/lib/libc.a:memcpy.o" + .include "tools/agbcc/lib/libc.a:memset.o" + .include "tools/agbcc/lib/libc.a:strcmp.o" + .include "tools/agbcc/lib/libc.a:strcpy.o" + .include "tools/agbcc/lib/libc.a:impure.o" + .include "tools/agbcc/lib/libc.a:vsprintf.o" + .include "tools/agbcc/lib/libc.a:vfprintf.o" + .include "tools/agbcc/lib/libc.a:wsetup.o" + .include "tools/agbcc/lib/libc.a:dtoa.o" + .include "tools/agbcc/lib/libc.a:fflush.o" + .include "tools/agbcc/lib/libc.a:findfp.o" + .include "tools/agbcc/lib/libc.a:freer.o" + .include "tools/agbcc/lib/libc.a:mtrim.o" + .include "tools/agbcc/lib/libc.a:fvwrite.o" + .include "tools/agbcc/lib/libc.a:fwalk.o" + .include "tools/agbcc/lib/libc.a:locale.o" + .include "tools/agbcc/lib/libc.a:makebuf.o" + .include "tools/agbcc/lib/libc.a:mallocr.o" + .include "tools/agbcc/lib/libc.a:mbtowc_r.o" + .include "tools/agbcc/lib/libc.a:memchr.o" + .include "tools/agbcc/lib/libc.a:memmove.o" + .include "tools/agbcc/lib/libc.a:mlock.o" + .include "tools/agbcc/lib/libc.a:mprec.o" + .include "tools/agbcc/lib/libc.a:s_isinf.o" + .include "tools/agbcc/lib/libc.a:s_isnan.o" + .include "tools/agbcc/lib/libc.a:sbrkr.o" + .include "tools/agbcc/lib/libc.a:stdio.o" + .include "tools/agbcc/lib/libc.a:strlen.o" + .include "tools/agbcc/lib/libc.a:syscalls.o" + .include "tools/agbcc/lib/libc.a:writer.o" + .include "tools/agbcc/lib/libc.a:callocr.o" + .include "tools/agbcc/lib/libc.a:closer.o" + .include "tools/agbcc/lib/libc.a:errno.o" + .include "tools/agbcc/lib/libc.a:fstatr.o" + .include "tools/agbcc/lib/libc.a:libcfunc.o" + .include "tools/agbcc/lib/libc.a:lseekr.o" + .include "tools/agbcc/lib/libc.a:readr.o" |