我遇到各种打印命令的问题
每当我试图调用printf()时,我的系统就会挂起或有时会重置
我有工作UART,我可以用UART_PutChar()打印到我的控制台就好了
fprintf适用于只打印普通字符串fprintf(stdout, "test\n");
的简单情况
但格式化的字符串会挂起我的系统fprintf(stdout, "test %d\n", 1);
当我尝试从.data部分打印数据时,也会发生挂起
char* dataString = "test\n\0";
int main(){
fprintf(stdout, dataString);
}
当我打印换行符printf("\n");
时,printf将起作用 如果我执行类似
的操作,printf将只打印换行符fputc('B', stdin); //notice stdin
printf("test\n"); //prints newline
在某些情况下,当fprintf失败时,它将返回EOF(现在不能记住它们,如果相关则会明天提供它们)
(f)printf似乎在调用putchar,我已将其重新定位到UART
奇怪的是我认为应该调用newlib-nano提供的_write
或_write_r
例程(而printf不会调用它们)。
作为IDE我正在使用EmBitz和它提供的工具链(arm-none-eabi)。我正在使用的CPU是at91sam7x128。我无法使用JTAG调试我的程序,因此我只需要尝试使用UART进行调试。
char* dataSection = "data\n\0";
char* dataSingle = "A";
int bssSection = 0;
int main(){
fprintf(stdout, "plain\n"); //works
fprintf(stdout, dataSingle); //works
fprintf(stdout, *(char*)(bssSection + 0x41)); //prints A, works
printf("\n"); //works
fprintf(stdout, "%d", 1); //hangs
fprintf(stdout, dataSection); //hangs
printf("plain printf\n"); //hangs
}
更新 启动脚本: SAM7.s
/*********************************************************************
*
* Defines, used for the processor status register
*
**********************************************************************
*/
ARM_MODE_USER = 0x10 /* Normal User Mode */
ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */
ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */
ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */
ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */
ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */
ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */
ARM_MODE_MASK = 0x1F
I_BIT = 0x80 /* Disables IRQ when I bit is set */
F_BIT = 0x40 /* Disables FIQ when F bit is set */
/*********************************************************************
*
* Vector table
*
**********************************************************************
*/
.text
.global __vector
.global _exit
.extern Reset_Handler
.arm
.section .vectors, "ax"
__vector:
ldr pc,Reset_Addr /* RESET vector */
Reset_Addr: .word Reset_Handler
__vector_end:
/*********************************************************************
*
* Standard C (crt0) initialization function
*
**********************************************************************
*/
.global OS_GetStackInfo
.extern __low_level_init
.extern main
crt0:
/*
* Call __low_level_init to initiliaze hardware
* before calling c-standard startup
*/
ldr r0,=__low_level_init
mov lr, pc
bx r0
/*
* Relocate .data section
* (Copy from ROM to RAM)
*/
ldr r1, =_etext
ldr r2, =_data
ldr r3, =_edata
LoopRel:
cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo LoopRel
/*
* Clear .bss section
*/
ldr r1, =__bss_start__
ldr r2, =__bss_end__
ldr r3, =0
bss_clear_loop:
cmp r1, r2
strne r3, [r1], #+4
bne bss_clear_loop
/*
* Prepare and call main()
*/
mrs r0, cpsr
bic r0, r0, #(I_BIT | F_BIT) /* Enable FIQ and IRQ interrupt */
msr cpsr, r0
mov r0, #0 /* No arguments are passed to main */
mov r1, #0
ldr r2, =main
mov lr, pc
bx r2
_exit: b _exit /* We should never come to here, just for sureness. */
/*********************************************************************
*
* __low_level_init
*
**********************************************************************
*/
__low_level_init:
bx lr
.weak __low_level_init
/**********************************************************************
* Reset_Handler
*
* Execution starts here.
* After a reset, the mode is ARM, Supervisor, interrupts disabled.
*/
.global Reset_Handler
.global end
.arm
.section .text, "ax"
Reset_Handler:
/*
* Setup a stack for each mode
*/
msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */
ldr sp, =__stack_und_end__
msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */
ldr sp, =__stack_abt_end__
msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */
ldr sp, =__stack_fiq_end__
msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */
ldr sp, =__stack_irq_end__
msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */
ldr sp, =__stack_svc_end__
/*
* Now enter crt0 function,
* which does low-level and segment initialization.
* and then calls main().
*/
ldr r0, =crt0
mov lr, pc
bx r0
end: b end
.end
链接描述文件
ENTRY(__vector)
/*********************************************************************
*
* Define stack sizes here
*/
FIQ_STACK_SIZE = 0x0;
IRQ_STACK_SIZE = 0x1000;
ABT_STACK_SIZE = 0x0;
UND_STACK_SIZE = 0x0;
SVC_STACK_SIZE = 0x1000;
MEMORY
{
RAM (wx) : ORIGIN = 0x200000, LENGTH = 0x8000
FLASH (rx) : ORIGIN = 0x100000, LENGTH = 0x10000
}
SECTIONS
{
.text :
{
*(.vectors);
. = ALIGN(8);
*(.init);
. = ALIGN(8);
*(.text);
. = ALIGN(8);
*(.rodata);
. = ALIGN(8);
*(.rodata*);
. = ALIGN(8);
*(.glue_7t);
. = ALIGN(8);
*(.glue_7);
. = ALIGN(8);
etext = .;
} > FLASH
. = ALIGN(8);
_etext = . ;
PROVIDE (etext = .);
.data : AT (_etext)
{
PROVIDE (__data_start__ = .);
_data = . ;
*(.data)
. = ALIGN(8);
PROVIDE (__data_end__ = .);
} > RAM
. = ALIGN(8);
_edata = . ;
PROVIDE (edata = .);
.bss :
{
PROVIDE (__bss_start__ = .);
*(.bss)
*(COMMON)
. = ALIGN(8);
PROVIDE (__bss_end__ = .);
. = ALIGN(256);
PROVIDE (__stack_start__ = .);
PROVIDE (__stack_fiq_start__ = .);
. += FIQ_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_fiq_end__ = .);
PROVIDE (__stack_irq_start__ = .);
. += IRQ_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_irq_end__ = .);
PROVIDE (__stack_abt_start__ = .);
. += ABT_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_abt_end__ = .);
PROVIDE (__stack_und_start__ = .);
. += UND_STACK_SIZE;
. = ALIGN(8);
PROVIDE (__stack_und_end__ = .);
PROVIDE (__stack_svc_start__ = .);
PROVIDE (__stack_svc_end__ = .);
PROVIDE (__stack_end__ = .);
PROVIDE (__heap_start__ = .);
. += 0x1000;
. = ALIGN(8);
PROVIDE (__heap_end__ = .);
} > RAM
}
更新2 我快速而又脏的系统调用重新实现。
int _write(int fd, char* buf, int len){
LED_On(1);
while(*buf){
UART_PutChar(*buf++);
}
return len;
}
void _ttywrch(int ch) {
LED_On(1);
UART_PutChar(ch);
}
signed int
putchar(signed int c)
{
return fputc(c, stdout);
}
signed int
fputs(const char* pStr, FILE* pStream)
{
signed int num = 0;
while (*pStr != 0)
{
if (fputc(*pStr, pStream) == -1)
{
return -1;
}
num++;
pStr++;
}
return num;
}
int
fputc(int c, FILE* pStream)
{
if ((pStream == stdout) || (pStream == stderr))
{
#ifdef UART_CONSOLE_CRLF
if (c == '\n')
UART_PutChar('\r');
#endif
UART_PutChar(c);
return c;
}
else
{
return EOF;
}
}
答案 0 :(得分:1)
您签名的putchar()
实施非常糟糕。这些系统调用旨在成为更高级别库(如stdio)使用的最低级别I / O例程。你无法使用 stdio实现它们!你毫无疑问会导致一个递归调用,它不会输出任何东西,也会很快溢出堆栈 - 之后什么都可能发生,但没什么好处。
int putchar( signed int c )
{
UART_PutChar( c ) ;
}
您的_write()
实施也不安全且在语义上不正确。它假设buf
是一个以空字符结尾的字符串,绝不需要这样 - 你应该使用len
参数来准确输出调用者请求的内容:
int _write( int fd, char* buf, int len )
{
fd = fd ;
for( int i = 0; i < len; i++ )
{
UART_PutChar( buf[i] );
}
return i ;
}
永远不会调用_write()
的原因是因为您通过重新实现fputs()
和fputc()
来规避它 - 覆盖仅依赖 的newlib实现系统调用。
你必须意识到这些例程是图书馆依赖于正常工作的基础 - “快速和肮脏”不够好;安全,简单和语义精确是你应该瞄准的目标。
答案 1 :(得分:0)
printf()
通常需要相当多的支持。特别是,需要实现_write()
函数,但是您成功输出的简单字符串表明存在并且有效。
相反,您的问题看起来可能是在printf()需要分配内存的情况下出现的。通过一长串依赖关系,这最终可以通过一个简单的malloc()并最终调用您的
实现void *_sbrk(int increment)
增加堆大小。如果您没有这样的实现,或者它失败或与其他区域发生冲突,它可以很容易地解释为什么您的故障仅发生在需要一起拼接生成的输出上。