0

我在使用各种打印命令时遇到问题。
每次我尝试调用 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 会起作用printf("\n");
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;
   }
}
4

2 回答 2

1

您签名putchar()的实现非常糟糕。这些系统调用旨在成为更高级别的库(例如 stdio)使用的最低级别的 I/O 例程。您不能使用stdio来实现它们!毫无疑问,您导致了一个不会输出任何内容并且还会快速溢出堆栈的递归调用 - 此后任何事情都可能发生,但没有任何好处。

int putchar( signed int c )
{
   UART_PutChar( c ) ;
}

您的_write()实现也不安全且语义不正确。它假定这buf是一个以 nul 结尾的字符串,但永远不会是这种情况 - 您应该使用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 实现来规避它。

您必须意识到,这些例程是库正常工作所依赖的基础——“快速和肮脏”还不够好;安全、简单和语义精确是您应该追求的目标。

于 2016-06-02T17:00:00.520 回答
0

printf()这种类型的嵌入式系统通常需要相当多的支持。特别是,需要实现一个_write()函数,但是您成功输出的简单字符串表明它存在并且有效。

相反,您的问题看起来可能出现在 printf() 需要分配内存的情况下。通过一长串的依赖关系,这最终可以通过一个简单的 malloc() 并最终调用您的实现

void *_sbrk(int increment)

增加堆大小。如果您没有实现它,或者如果它失败或与其他区域发生冲突,它可以很容易地解释为什么您的失败只发生在需要拼凑生成的输出上。

于 2016-06-01T19:54:32.227 回答