Library Retarget File
Semihosting is not supported by MDK-ARM. Use the retargeting functionality of MDK-ARM instead. To prevent the linker from selecting libraries functions that use semihosting, MDK-ARM includes retarget files that redefine low-level I/O routines.
A RETARGET.C template file, located in the folder ..\ARM\Startup, implements the functionality required to adapt character I/O functions such as printf() and scanf().
- Copy the RETARGET.C template to the project folder.
- Include the copied file to the project (described in Create Source File).
- Edit the file and make your changes. You may use the following code as a template and adapt it to your needs.
/*---------------------------------------------------------------------------- * Name: Retarget.c * Purpose: 'Retarget' layer for target-dependent low level functions * Note(s): *---------------------------------------------------------------------------- * This file is part of the µVision/ARM development tools. * This software may only be used under the terms of a valid, current, * end user licence from KEIL for a compatible version of KEIL software * development tools. Nothing else gives you the right to use this software. * * This software is supplied "AS IS" without warranties of any kind. * * Copyright (c) 2009 Keil - An ARM Company. All rights reserved. *----------------------------------------------------------------------------*/ #include <stdio.h> #include <rt_misc.h> #pragma import(__use_no_semihosting_swi) extern int sendchar (int c); extern int getkey (void); struct __FILE { int handle; /* Add whatever you need here */ }; FILE __stdout; FILE __stdin; int fputc(int c, FILE *f) { return (sendchar(c)); } int fgetc(FILE *f) { return (getkey()); } int ferror(FILE *f) { /* Your implementation of ferror */ return EOF; } void _ttywrch(int c) { sendchar(c); } void _sys_exit(int return_code) { label: goto label; /* endless loop */ }
Note
- Refer to Tailoring the C library to a new execution environment for information about library retargeting.
- Refer to Redefining target-dependent system I/O functions in the C library.
- Refer to Redefining low-level library functions to enable direct use of high-level library functions in the C library
- Refer to What is semihosting?
Tailoring the C library to a new execution environment
1.41 Tailoring the C library to a new execution environment
Tailoring the C library to a new execution environment involves re-implementing functions to produce an application for a new execution environment, for example, embedded in ROM or used with an RTOS.
Related concepts
Redefining target-dependent system I/O functions in the C library
1.78 Redefining target-dependent system I/O functions in the C library
The default target-dependent I/O functions use semihosting. If any of these functions are redefined, then they must all be redefined.
Retargeting the system I/O functions
FILEHANDLE _sys_open(const char *name, int openmode) { return 1; /* everything goes to the same output */ } int _sys_close(FILEHANDLE fh) { return 0; } int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) { your_device_write(buf, len); return 0; } int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) { return -1; /* not supported */ } void _ttywrch(int ch) { char c = ch; your_device_write(&c, 1); } int _sys_istty(FILEHANDLE fh) { return 0; /* buffered output */ } int _sys_seek(FILEHANDLE fh, long pos) { return -1; /* not supported */ } long _sys_flen(FILEHANDLE fh) { return -1; /* not supported */ }
FILEHANDLE
. The value of
FILEHANDLE
is returned by
_sys_open()
and identifies an open file on the host system.
Related concepts
Redefining low-level library functions to enable direct use of high-level library functions in the C library
1.74 Redefining low-level library functions to enable direct use of high-level library functions in the C library
If you define your own version of __FILE
, your own fputc()
and ferror()
functions, and the __stdout
object, you can use all of the printf()
family, fwrite()
, fputs()
, puts() and
the C++ object std::cout
unchanged from the library.
Retargeting printf()
#include <stdio.h> struct __FILE { int handle; /* Whatever you require here. If the only file you are using is */ /* standard output using printf() for debugging, no file handling */ /* is required. */ }; /* FILE is typedef’d in stdio.h. */ FILE __stdout; int fputc(int ch, FILE *f) { /* Your implementation of fputc(). */ return ch; } int ferror(FILE *f) { /* Your implementation of ferror(). */ return 0; } void test(void) { printf("Hello world\n"); }
Note
fputc()
.
fputc()
takes an
int
parameter, but contains only a character. Whether the character is in the first or the last byte of the integer variable depends on the endianness. The following code sample avoids problems with endianness:
extern void sendchar(char *ch); int fputc(int ch, FILE *f) { /* example: write a character to an LCD */ char tempch = ch; // temp char avoids endianness issue sendchar(&tempch); return ch; }
Retargeting cout
#include <stdio.h> namespace std { struct __FILE { int handle; /* Whatever you require here. If the only file you are using is */ /* standard output using printf() for debugging, no file handling */ /* is required. */ }; FILE __stdout; FILE __stdin; FILE __stderr; int fgetc(FILE *f) { /* Your implementation of fgetc(). */ return 0; }; int fputc(int c, FILE *stream) { /* Your implementation of fputc(). */ } int ferror(FILE *stream) { /* Your implementation of ferror(). */ } long int ftell(FILE *stream) { /* Your implementation of ftell(). */ } int fclose(FILE *f) { /* Your implementation of fclose(). */ return 0; } int fseek(FILE *f, long nPos, int nMode) { /* Your implementation of fseek(). */ return 0; } int fflush(FILE *f) { /* Your implementation of fflush(). */ return 0; } }
#include <stdio.h> #include <iostream> using namespace std; int main() { cout << "Hello world\n"; return 0; }
fread()
and
fwrite()
call fast block input/output functions that are part of the ARM stream implementation. If you define your own
__FILE
structure instead of using the ARM stream implementation,
fread()
and
fwrite()
call
fgetc()
instead of calling the block input/output functions.
Related concepts
What is semihosting?
Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.
Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf()
and scanf()
, to use the screen and keyboard of the host instead of having a screen and keyboard on the target system.
This is useful because development hardware often does not have all the input and output facilities of the final system. Semihosting enables the host computer to provide these facilities.
Semihosting is implemented by a set of defined software instructions, for example, SVCs, that generate exceptions from program control. The application invokes the appropriate semihosting call and the debug agent then handles the exception. The debug agent provides the required communication with the host.
The semihosting interface is common across all debug agents provided by ARM. Semihosted operations work when you are debugging applications on your development platform, as shown in the following figure:
In many cases, semihosting is invoked by code within library functions. The application can also invoke the semihosting operation directly.
Note
ARM processors prior to ARMv7 use the SVC
instructions, formerly known as SWI
instructions, to make semihosting calls. However, if you are compiling for an ARMv6-M or ARMv7-M, for example a Cortex-M1 or Cortex-M3 processor, semihosting is implemented using the BKPT
instruction.
-
Concepts
-
Using ARM C and C++ Libraries and Floating Point Support:
Reference