I am working in a bare-metal ARM project in which I am trying to integrate newlib library. As a beginner, I am trying to make the printf
function working first so that I can see the standard output through UART. I have already gone through many on-line documents that describes how to get this done. Instead of blindly following the steps, I did everything myself by learning things from those documents. I made many mistakes in the beginning but fixed them one by one and kept the work progressing.
But now I have stuck with an issue which no one has ever seems to be experienced so far, according to my internet search. Now let me come to the actual, issue.
The printf
function is returning without calling my implementation of _write
function. When I debug I can see that the printf
is invoking other system calls that I have written myself(Like _isatty
, _sbrk
and _fstat
).
These are the system calls that I have implemented in order to resolve the linking issues(undefined references)
extern char __heap_start__;
extern char __heap_end__;
void _exit(int status)
{
while (1);
}
void *_sbrk(int incr)
{
static char *heap_end = &__heap_start__;
char *base = heap_end;
if(heap_end + incr > &__heap_end__)
{
errno = ENOMEM;
return (void *)-1;
}
heap_end += incr;
return base;
}
int _write(int fd, char *buff, int size)
{
int i;
for(i = 0; i < size; i++)
{
UART0_write_char(buff[i]);
}
return i;
}
int _read(int fd, char *buff, int size)
{
return 0;
}
int _open(const char *name, int flags,int mode)
{
return 0;
}
void _close(int fd)
{
}
int _isatty(int fd)
{
return 1;
}
int _fstat(int fd, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
off_t _lseek(int fd, off_t offset, int whence)
{
return 0;
}
My linker script
STACK_HEAP_BOUNDARY_OFFSET = 0;
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
SRAM (rw) : ORIGIN = 0x40000000, LENGTH = 32K
}
SECTIONS
{
.text :
{
startup.o (.text)
*(.text .txt.*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
.ARM :
{
*(.ARM.exidx*)
} >FLASH
.rodata :
{
*(.rodata .rodata.*)
. = ALIGN(4);
} > FLASH
.data :
{
__data_load__ = LOADADDR (.data);
__data_start__ = .;
*(.data .data.*)
. = ALIGN(4);
__data_end__ = .;
} > SRAM AT > FLASH
.bss :
{
__bss_start__ = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > SRAM
.heap :
{
__heap_start__ = .;
PROVIDE(end = __heap_start__);
PROVIDE(_heap_start = __heap_start__);
. = . + ((LENGTH(SRAM) - (. - (ORIGIN(SRAM)))) / 2);
. += STACK_HEAP_BOUNDARY_OFFSET;
. = ALIGN(4);
__heap_end__ = .;
PROVIDE(_heap_end = __heap_end__);
} > SRAM
.stack :
{
__stack_start__ = .;
. = . + (LENGTH(SRAM) - (. - (ORIGIN(SRAM))));
. = ALIGN(4);
__stack_end__ = .;
__stack_size__ = __stack_end__ - __stack_start__;
__IRQ_stack_top__ = (__stack_start__ + (__stack_size__ / 2));
} > SRAM
}
My Makefile
TOOLCHAIN_PREFIX:=arm-none-eabi-
CC := $(TOOLCHAIN_PREFIX)gcc
LD := $(TOOLCHAIN_PREFIX)ld
AS := $(TOOLCHAIN_PREFIX)as
AR := $(TOOLCHAIN_PREFIX)ar -cr
OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy
RM := rm -f
TARGET := image.hex
OBJS := startup.o $(patsubst %.c,%.o,$(wildcard *.c))
CFLAGS := -mcpu=arm7tdmi-s -g3 -Wall -I. -gdwarf-2
AS_FLAGS := -mcpu=arm7tdmi-s -g3 -gdwarf-2
LD_FLAGS := -Wl,-Map,$(TARGET:%.hex=%).map -nostartfiles
LD_SCRIPT := lpc2138.ld
all : $(TARGET)
$(TARGET) : $(TARGET:%.hex=%.elf)
$(OBJCOPY) -O ihex $< $@
$(TARGET:%.hex=%.elf) : $(OBJS)
$(CC) -o $@ -T $(LD_SCRIPT) $(OBJS) $(LD_FLAGS)
startup.o : startup.s
$(AS) $(AS_FLAGS) -o $@ $<
%.o : %.c
$(CC) -c $(CFLAGS) -o $@ $<
clean :
$(RM) $(TARGET) $(TARGET:%.hex=%.elf) $(TARGET:%.hex=%).map *.o
Please let me know if any further information is needed from my side. Thank you in advance
EDIT:
Start-up code
/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */
Mode_USR = 0x10
Mode_FIQ = 0x11
Mode_IRQ = 0x12
Mode_SVC = 0x13
Mode_ABT = 0x17
Mode_UND = 0x1B
Mode_SYS = 0x1F
I_Bit = 0x80 /* when I bit is set, IRQ is disabled */
F_Bit = 0x40 /* when F bit is set, FIQ is disabled */
.text
.arm
.global _start
.func _start
_start:
B _reset /* Reset vector */
B _loop /* Undefined Instruction */
B _loop /* Software Interrupt */
B _loop /* Prefetch Abort */
B _loop /* Data Abort */
NOP /* Reserved */
LDR pc, [pc, #-0x0FF0] /* VicVectAddr */
/* LDR pc, _fiq_addr */
B _loop /* FIQ Handler */
_reset:
/* Enable FIQ and IRQ */
MSR CPSR_c,#(Mode_IRQ | I_Bit | F_Bit)
LDR SP, =__IRQ_stack_top__
MSR CPSR_c,#Mode_SVC
/* Relocate the .data section (copy from ROM to RAM) */
LDR r0,=__data_load__
LDR r1,=__data_start__
LDR r2,=__data_end__
_l1:
CMP r1,r2
LDMLTIA r0!,{r3}
STMLTIA r1!,{r3}
BLT _l1
/* Clear the .bss section (zero init) */
LDR r1,=__bss_start__
LDR r2,=__bss_end__
MOV r3,#0
_l2:
CMP r1,r2
STMLTIA r1!,{r3}
BLT _l2
LDR sp,=__stack_end__
LDR FP,=__stack_end__
LDR r0,=main
MOV lr,pc
BX r0
_loop:
B _loop
/* _fiq_addr:
.word VIC_FIQ_handler
*/
.endfunc
.end
User contributions licensed under CC BY-SA 3.0