From 084ca2325cdc05acfbe61e80e8c88a3853fecae3 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Wed, 6 Aug 2014 15:00:33 +0400 Subject: [PATCH] Implementing __printf. Setting libc_raw as default libc. Removing LIBC_STD mode. --- Makefile | 3 +- Makefile.mk | 79 ++- src/libruntime/jerry-libc-printf.c | 699 +++++++++++++++++++++ src/libruntime/jerry-libc.h | 37 +- src/libruntime/target/linux/asm_x64.h | 24 +- src/libruntime/target/linux/jerry-libc.c | 125 +--- src/libruntime/target/stm32f4/jerry-libc.c | 42 +- 7 files changed, 812 insertions(+), 197 deletions(-) create mode 100644 src/libruntime/jerry-libc-printf.c diff --git a/Makefile b/Makefile index 397ccddf0..59728ec14 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,7 @@ export TARGET_MODES = debug debug_release release export TARGET_PC_SYSTEMS = linux export TARGET_MCU_SYSTEMS = $(addprefix stm32f,4) # now only stm32f4 is supported, to add, for example, to stm32f3, change to $(addprefix stm32f,3 4) -export TARGET_PC_MODS = libc_raw musl sanitize valgrind \ - libc_raw-sanitize libc_raw-valgrind \ +export TARGET_PC_MODS = musl sanitize valgrind \ musl-valgrind export TARGET_MCU_MODS = diff --git a/Makefile.mk b/Makefile.mk index 168b24e56..8255294e7 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -50,6 +50,13 @@ TARGET_DIR=$(OUT_DIR)/$(TARGET_MODE).$(TARGET_SYSTEM_AND_MODS) # Options setup # +# Is MCU target? +ifeq ($(filter-out $(TARGET_MCU_SYSTEMS),$(TARGET_SYSTEM)),) + OPTION_MCU = enable +else + OPTION_MCU = disable +endif + # DWARF version ifeq ($(dwarf4),1) OPTION_DWARF4 := enable @@ -79,6 +86,10 @@ endif # -fdiagnostics-color=always ifeq ($(color),1) + ifeq ($(OPTION_MCU),enable) + $(error MCU target doesn\'t support coloring compiler's output) + endif + OPTION_COLOR := enable else OPTION_COLOR := disable @@ -102,31 +113,18 @@ else OPTION_OPTIMIZE = disable endif -# Is MCU target? -ifeq ($(filter-out $(TARGET_MCU_SYSTEMS),$(TARGET_SYSTEM)),) - OPTION_MCU = enable -else - OPTION_MCU = disable -endif - ifeq ($(filter musl,$(TARGET_MODS)), musl) - OPTION_LIBC_MUSL := enable -else - OPTION_LIBC_MUSL := disable -endif - -ifeq ($(filter libc_raw,$(TARGET_MODS)), libc_raw) - ifeq ($(OPTION_LIBC_MUSL),enable) - $(error LIBC_RAW and LIBC_MUSL are mutually exclusive) + ifeq ($(OPTION_MCU),enable) + $(error MCU target doesn\'t support LIBC_MUSL) endif - OPTION_LIBC_RAW := enable + OPTION_LIBC := musl else - OPTION_LIBC_RAW := disable + OPTION_LIBC := raw endif ifeq ($(filter sanitize,$(TARGET_MODS)), sanitize) - ifeq ($(OPTION_LIBC_MUSL),enable) + ifeq ($(OPTION_LIBC),musl) $(error ASAN and LIBC_MUSL are mutually exclusive) endif @@ -266,6 +264,21 @@ INCLUDES_JERRY = \ -I src/liboptimizer \ -I src/libcoreint +# libc +ifeq ($(OPTION_LIBC),musl) + CC := musl-$(CC) + DEFINES_JERRY += -DLIBC_MUSL + CFLAGS_COMMON += -static +else + DEFINES_JERRY += -DLIBC_RAW + CFLAGS_COMMON += -nostdlib + + ifeq ($(OPTION_SANITIZE),enable) + CFLAGS_COMMON += -fsanitize=address + LDFLAGS += -lasan + endif +endif + ifeq ($(OPTION_NDEBUG),enable) DEFINES_JERRY += -DJERRY_NDEBUG endif @@ -273,35 +286,15 @@ endif ifeq ($(OPTION_MCU),disable) DEFINES_JERRY += -D__TARGET_HOST_x64 -DJERRY_SOURCE_BUFFER_SIZE=$$((1024*1024)) CFLAGS_COMMON += -fno-stack-protector - - ifeq ($(OPTION_LIBC_MUSL),enable) - CC := musl-$(CC) - DEFINES_JERRY += -DLIBC_MUSL - CFLAGS_COMMON += -static - else - ifeq ($(OPTION_SANITIZE),enable) - CFLAGS_COMMON += -fsanitize=address - endif - - ifeq ($(OPTION_LIBC_RAW),enable) - DEFINES_JERRY += -DLIBC_RAW - CFLAGS_COMMON += -nostdlib - ifeq ($(OPTION_SANITIZE),enable) - LDFLAGS += -lasan - endif - else - CFLAGS_COMMON += -DLIBC_STD - endif - endif - - ifeq ($(OPTION_COLOR),enable) - CFLAGS_COMMON += -fdiagnostics-color=always - endif else CFLAGS_COMMON += -ffunction-sections -fdata-sections -nostdlib DEFINES_JERRY += -D__TARGET_MCU endif +ifeq ($(OPTION_COLOR),enable) + CFLAGS_COMMON += -fdiagnostics-color=always +endif + ifeq ($(OPTION_TODO),enable) DEFINES_JERRY += -DJERRY_PRINT_TODO endif @@ -404,7 +397,7 @@ $(TESTS_TARGET): @for unit_test in $(SOURCES_UNITTESTS); \ do \ cmd="$(CC) $(DEFINES_JERRY) $(CFLAGS_COMMON) $(CFLAGS_JERRY) \ - $(INCLUDES_JERRY) $(INCLUDES_THIRDPARTY) $(TARGET_DIR)/obj/*.o $(UNITTESTS_SRC_DIR)/$$unit_test.c -o $(TARGET_DIR)/$$unit_test"; \ + $(INCLUDES_JERRY) $(INCLUDES_THIRDPARTY) $(TARGET_DIR)/obj/*.o $(UNITTESTS_SRC_DIR)/$$unit_test.c -lc -o $(TARGET_DIR)/$$unit_test"; \ if [ "$(OPTION_ECHO)" = "enable" ]; then echo $$cmd; echo; fi; \ $$cmd; \ if [ $$? -ne 0 ]; then echo Failed "'$$cmd'"; exit 1; fi; \ diff --git a/src/libruntime/jerry-libc-printf.c b/src/libruntime/jerry-libc-printf.c new file mode 100644 index 000000000..b79e3963a --- /dev/null +++ b/src/libruntime/jerry-libc-printf.c @@ -0,0 +1,699 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Jerry printf implementation + */ + +#include "globals.h" +#include "jerry-libc.h" + +#include + +/** + * printf's length type + */ +typedef enum +{ + LIBC_PRINTF_ARG_LENGTH_TYPE_NONE, /**< (none) */ + LIBC_PRINTF_ARG_LENGTH_TYPE_HH, /**< hh */ + LIBC_PRINTF_ARG_LENGTH_TYPE_H, /**< h */ + LIBC_PRINTF_ARG_LENGTH_TYPE_L, /**< l */ + LIBC_PRINTF_ARG_LENGTH_TYPE_LL, /**< ll */ + LIBC_PRINTF_ARG_LENGTH_TYPE_J, /**< j */ + LIBC_PRINTF_ARG_LENGTH_TYPE_Z, /**< z */ + LIBC_PRINTF_ARG_LENGTH_TYPE_T, /**< t */ + LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL /**< L */ +} libc_printf_arg_length_type_t; + +/** + * printf's flags mask + */ +typedef uint8_t libc_printf_arg_flags_mask_t; + +/** + * Left justification of field's contents + */ +#define LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY ( 1 << 0 ) + +/** + * Force print of number's sign + */ +#define LIBC_PRINTF_ARG_FLAG_PRINT_SIGN ( 1 << 1 ) + +/** + * If no sign is printed, print space before value + */ +#define LIBC_PRINTF_ARG_FLAG_SPACE ( 1 << 2 ) + +/** + * For o, x, X preceed value with 0, 0x or 0X for non-zero values. + */ +#define LIBC_PRINTF_ARG_FLAG_SHARP ( 1 << 3 ) + +/** + * Left-pad field with zeroes instead of spaces + */ +#define LIBC_PRINTF_ARG_FLAG_ZERO_PADDING ( 1 << 4 ) + +/** + * printf helper function that outputs a char + */ +static void +libc_printf_putchar( _FILE *stream, /**< stream pointer */ + char character) /**< character */ +{ + __fwrite( &character, 1, sizeof(character), stream); +} /* libc_printf_putchar */ + +/** + * printf helper function that outputs justified string + */ +static void +libc_printf_justified_string_output( _FILE *stream, /**< stream pointer */ + const char *string_p, /**< string */ + size_t width, /**< minimum field width */ + bool is_left_justify, /**< justify to left (true) or right (false) */ + bool is_zero_padding) /**< left-pad with zeroes (true) or spaces (false) */ +{ + const size_t str_length = __strlen( string_p); + + size_t outputted_length = 0; + + if ( !is_left_justify ) + { + char padding_char = is_zero_padding ? '0' : ' '; + + while ( outputted_length + str_length < width ) + { + libc_printf_putchar( stream, padding_char); + outputted_length++; + } + } + + __fwrite( string_p, 1, str_length * sizeof(*string_p), stream); + outputted_length += str_length; + + if ( is_left_justify ) + { + while( outputted_length < width ) + { + libc_printf_putchar( stream, ' '); + outputted_length++; + } + } +} /* libc_printf_justified_string_output */ + +/** + * printf helper function that converts unsigned integer to string + */ +static char* +libc_printf_uint_to_string( uintmax_t value, /**< integer value */ + char *buffer_p, /**< buffer for output string */ + size_t buffer_size, /**< buffer size */ + const char *alphabet, /**< alphabet used for digits */ + uint32_t radix) /**< radix */ +{ + char *str_buffer_end = buffer_p + buffer_size; + char *str_p = str_buffer_end; + *--str_p = '\0'; + + JERRY_ASSERT( radix >= 2 ); + + if ( ( radix & ( radix - 1 ) ) != 0 ) + { + /* + * Radix is not power of 2. Only 32-bit numbers are supported in this mode. + */ + JERRY_ASSERT( ( value >> 32 ) == 0 ); + + uint32_t value_lo = (uint32_t) value; + + while ( value_lo != 0 ) + { + JERRY_ASSERT ( str_p != buffer_p ); + + *--str_p = alphabet[ value_lo % radix ]; + value_lo /= radix; + } + } + else + { + uint32_t shift = 0; + while ( !( radix & ( 1u << shift ) ) ) + { + shift++; + + JERRY_ASSERT( shift <= 32 ); + } + + uint32_t value_lo = (uint32_t) value; + uint32_t value_hi = (uint32_t) ( value >> 32 ); + + while ( value_lo != 0 + || value_hi != 0 ) + { + JERRY_ASSERT ( str_p != buffer_p ); + + *--str_p = alphabet[ value_lo & ( radix - 1 ) ]; + value_lo >>= shift; + value_lo += ( value_hi & ( radix - 1 ) ) << ( 32 - shift ); + value_hi >>= shift; + } + } + + if ( *str_p == '\0' ) + { + *--str_p = '0'; + } + + JERRY_ASSERT( str_p >= buffer_p && str_p < str_buffer_end ); + + return str_p; +} /* libc_printf_uint_to_string */ + +/** + * printf helper function that prints d and i arguments + * + * @return updated va_list + */ +static void +libc_printf_write_d_i( _FILE *stream, /**< stream pointer */ + va_list* args_list_p, /**< args' list */ + libc_printf_arg_flags_mask_t flags, /**< field's flags */ + libc_printf_arg_length_type_t length, /**< field's length type */ + uint32_t width) /**< minimum field width to output */ +{ + JERRY_ASSERT( ( flags & LIBC_PRINTF_ARG_FLAG_SHARP ) == 0 ); + + bool is_signed = true; + uintmax_t value = 0; + + /* true - positive, false - negative */ + bool sign = true; + const uintmax_t value_sign_mask = ((uintmax_t)1) << ( sizeof(value) * JERRY_BITSINBYTE - 1 ); + + switch ( length ) + { + case LIBC_PRINTF_ARG_LENGTH_TYPE_NONE: + value = (uintmax_t)va_arg( *args_list_p, int); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_HH: + value = (uintmax_t)va_arg( *args_list_p, int); /* char is promoted to int */ + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_H: + value = (uintmax_t)va_arg( *args_list_p, int); /* short int is promoted to int */ + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_L: + value = (uintmax_t)va_arg( *args_list_p, long int); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_LL: + value = (uintmax_t)va_arg( *args_list_p, long long int); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_J: + value = (uintmax_t)va_arg( *args_list_p, intmax_t); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_Z: + is_signed = false; + value = (uintmax_t)va_arg( *args_list_p, size_t); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_T: + is_signed = false; + value = (uintmax_t)va_arg( *args_list_p, ptrdiff_t); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL: + JERRY_UNREACHABLE(); + } + + if ( is_signed ) + { + sign = ( ( value & value_sign_mask ) == 0 ); + + if ( !sign ) + { + value = (uintmax_t) (-value); + } + } + + char str_buffer[ 32 ]; + const char *string_p = libc_printf_uint_to_string( value, + str_buffer, + sizeof(str_buffer), + "0123456789", + 10); + + if ( !sign + || ( flags & LIBC_PRINTF_ARG_FLAG_PRINT_SIGN ) ) + { + /* printing sign */ + + libc_printf_putchar( stream, sign ? '+' : '-' ); + if ( width > 0 ) + { + width--; + } + } + else if ( flags & LIBC_PRINTF_ARG_FLAG_SPACE ) + { + /* no sign and space flag, printing one space */ + + libc_printf_putchar( stream, ' '); + if ( width > 0 ) + { + width--; + } + } + + libc_printf_justified_string_output( stream, + string_p, + width, + flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY, + flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING); +} /** libc_printf_write_d_i */ + +/** + * printf helper function that prints d and i arguments + * + * @return updated va_list + */ +static void +libc_printf_write_u_o_x_X( _FILE *stream, /**< stream pointer */ + char specifier, /**< specifier (u, o, x, X) */ + va_list* args_list_p, /**< args' list */ + libc_printf_arg_flags_mask_t flags, /**< field's flags */ + libc_printf_arg_length_type_t length, /**< field's length type */ + uint32_t width) /**< minimum field width to output */ +{ + uintmax_t value = 0; + + switch ( length ) + { + case LIBC_PRINTF_ARG_LENGTH_TYPE_NONE: + value = (uintmax_t)va_arg( *args_list_p, unsigned int); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_HH: + value = (uintmax_t)va_arg( *args_list_p, unsigned int); /* char is promoted to int */ + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_H: + value = (uintmax_t)va_arg( *args_list_p, unsigned int); /* short int is promoted to int */ + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_L: + value = (uintmax_t)va_arg( *args_list_p, unsigned long int); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_LL: + value = (uintmax_t)va_arg( *args_list_p, unsigned long long int); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_J: + value = (uintmax_t)va_arg( *args_list_p, uintmax_t); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_Z: + value = (uintmax_t)va_arg( *args_list_p, size_t); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_T: + value = (uintmax_t)va_arg( *args_list_p, ptrdiff_t); + break; + + case LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL: + JERRY_UNREACHABLE(); + } + + if ( flags & LIBC_PRINTF_ARG_FLAG_SHARP ) + { + if ( value != 0 && specifier != 'u' ) + { + libc_printf_putchar( stream, '0'); + + if ( specifier == 'x' ) + { + libc_printf_putchar( stream, 'x'); + } + else if ( specifier == 'X' ) + { + libc_printf_putchar( stream, 'X'); + } + else + { + JERRY_ASSERT( specifier == 'o' ); + } + } + } + + uint32_t radix = 10; + const char *alphabet; + + switch ( specifier ) + { + case 'u': + alphabet = "0123456789"; + radix = 10; + break; + + case 'o': + alphabet = "01234567"; + radix = 8; + break; + + case 'x': + alphabet = "0123456789abcdef"; + radix = 16; + break; + + case 'X': + alphabet = "0123456789ABCDEF"; + radix = 16; + break; + + default: + JERRY_UNREACHABLE(); + } + + char str_buffer[ 32 ]; + const char *string_p = libc_printf_uint_to_string( value, + str_buffer, + sizeof(str_buffer), + alphabet, + radix); + + if ( flags & LIBC_PRINTF_ARG_FLAG_PRINT_SIGN ) + { + /* printing sign */ + + libc_printf_putchar( stream, '+'); + if ( width > 0 ) + { + width--; + } + } + else if ( flags & LIBC_PRINTF_ARG_FLAG_SPACE ) + { + /* no sign and space flag, printing one space */ + + libc_printf_putchar( stream, ' '); + if ( width > 0 ) + { + width--; + } + } + + libc_printf_justified_string_output( stream, + string_p, + width, + flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY, + flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING); +} /** libc_printf_write_u_o_x_X */ + +/** + * vfprintf + * + * @return number of characters printed + */ +static int +__vfprintf( _FILE *stream, /**< stream pointer */ + const char *format, /**< format string */ + va_list args) /**< arguments */ +{ + va_list args_copy; + + va_copy( args_copy, args); + + const char *format_iter_p = format; + + while ( *format_iter_p ) + { + if ( *format_iter_p != '%' ) + { + libc_printf_putchar( stream, *format_iter_p); + } + else + { + libc_printf_arg_flags_mask_t flags = 0; + uint32_t width = 0; + libc_printf_arg_length_type_t length = LIBC_PRINTF_ARG_LENGTH_TYPE_NONE; + + while ( true ) + { + format_iter_p++; + + if ( *format_iter_p == '-' ) + { + flags |= LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY; + } + else if ( *format_iter_p == '+' ) + { + flags |= LIBC_PRINTF_ARG_FLAG_PRINT_SIGN; + } + else if ( *format_iter_p == ' ' ) + { + flags |= LIBC_PRINTF_ARG_FLAG_SPACE; + } + else if ( *format_iter_p == '#' ) + { + flags |= LIBC_PRINTF_ARG_FLAG_SHARP; + } + else if ( *format_iter_p == '0' ) + { + flags |= LIBC_PRINTF_ARG_FLAG_ZERO_PADDING; + } + else + { + break; + } + } + + if ( *format_iter_p == '*' ) + { + JERRY_UNIMPLEMENTED(); + } + + // If there is a number, recognize it as field width + while ( *format_iter_p >= '0' && *format_iter_p <= '9' ) + { + width = width * 10u + (uint32_t) (*format_iter_p - '0'); + + format_iter_p++; + } + + if ( *format_iter_p == '.' ) + { + JERRY_UNIMPLEMENTED(); + } + + switch ( *format_iter_p ) + { + case 'h': + format_iter_p++; + if ( *format_iter_p == 'h' ) + { + format_iter_p++; + + length = LIBC_PRINTF_ARG_LENGTH_TYPE_HH; + } + else + { + length = LIBC_PRINTF_ARG_LENGTH_TYPE_H; + } + break; + + case 'l': + format_iter_p++; + if ( *format_iter_p == 'l' ) + { + format_iter_p++; + + length = LIBC_PRINTF_ARG_LENGTH_TYPE_LL; + } + else + { + length = LIBC_PRINTF_ARG_LENGTH_TYPE_L; + } + break; + + case 'j': + format_iter_p++; + length = LIBC_PRINTF_ARG_LENGTH_TYPE_J; + break; + + case 'z': + format_iter_p++; + length = LIBC_PRINTF_ARG_LENGTH_TYPE_Z; + break; + + case 't': + format_iter_p++; + length = LIBC_PRINTF_ARG_LENGTH_TYPE_T; + break; + + case 'L': + format_iter_p++; + length = LIBC_PRINTF_ARG_LENGTH_TYPE_HIGHL; + break; + } + + switch ( *format_iter_p ) + { + case 'd': + case 'i': + libc_printf_write_d_i( stream, &args_copy, flags, length, width); + break; + + case 'u': + case 'o': + case 'x': + case 'X': + libc_printf_write_u_o_x_X( stream, *format_iter_p, &args_copy, flags, length, width); + break; + + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + JERRY_UNIMPLEMENTED(); + break; + + case 'c': + if ( length & LIBC_PRINTF_ARG_LENGTH_TYPE_L ) + { + JERRY_UNIMPLEMENTED(); + } + else + { + char str[2] = + { + (char)va_arg( args_copy, int), /* char is promoted to int */ + '\0' + }; + + libc_printf_justified_string_output( stream, + str, + width, + flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY, + flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING); + } + break; + + case 's': + if ( length & LIBC_PRINTF_ARG_LENGTH_TYPE_L ) + { + JERRY_UNIMPLEMENTED(); + } + else + { + char *str_p = va_arg( args_copy, char*); + + libc_printf_justified_string_output( stream, + str_p, + width, + flags & LIBC_PRINTF_ARG_FLAG_LEFT_JUSTIFY, + flags & LIBC_PRINTF_ARG_FLAG_ZERO_PADDING); + } + break; + + case 'p': + { + va_list args_copy2; + va_copy( args_copy2, args_copy); + void *value = va_arg( args_copy2, void*); + va_end( args_copy2); + + if ( value == NULL ) + { + __printf( "(nil)"); + } + else + { + libc_printf_write_u_o_x_X( stream, + 'x', + &args_copy, + flags | LIBC_PRINTF_ARG_FLAG_SHARP, + LIBC_PRINTF_ARG_LENGTH_TYPE_Z, + width); + } + } + break; + + case 'n': + JERRY_UNIMPLEMENTED(); + break; + } + } + + format_iter_p++; + } + + va_end( args_copy); + + return 0; +} /* __vfprintf */ + +/** + * fprintf + * + * @return number of characters printed + */ +int +__fprintf( _FILE *stream, /**< stream pointer */ + const char *format, /**< format string */ + ...) /**< parameters' values */ +{ + va_list args; + + va_start( args, format); + + int ret = __vfprintf( stream, format, args); + + va_end( args); + + return ret; +} /* __fprintf */ + +/** + * printf + * + * @return number of characters printed + */ +int +__printf( const char *format, /**< format string */ + ...) /**< parameters' values */ +{ + va_list args; + + va_start( args, format); + + int ret = __vfprintf( LIBC_STDOUT, format, args); + + va_end( args); + + return ret; +} /* __printf */ + diff --git a/src/libruntime/jerry-libc.h b/src/libruntime/jerry-libc.h index ee812c0a8..4b431445c 100644 --- a/src/libruntime/jerry-libc.h +++ b/src/libruntime/jerry-libc.h @@ -23,6 +23,42 @@ typedef void _FILE; +#ifdef LIBC_RAW +/** + * stdin file descriptor + */ +#define LIBC_STDIN (_FILE*)0 + +/** + * stdout file descriptor + */ +#define LIBC_STDOUT (_FILE*)1 + +/** + * stderr file descriptor + */ +#define LIBC_STDERR (_FILE*)2 +#else /* !LIBC_RAW */ +extern const _FILE **libc_stdin; +extern const _FILE **libc_stdout; +extern const _FILE **libc_stderr; + +/** + * stdin file descriptor + */ +#define LIBC_STDIN ((_FILE*)*libc_stdin) + +/** + * stdout file descriptor + */ +#define LIBC_STDOUT ((_FILE*)*libc_stdout) + +/** + * stderr file descriptor + */ +#define LIBC_STDERR ((_FILE*)*libc_stderr) +#endif /* !LIBC_RAW */ + extern void* __memset (void *s, int c, size_t n); extern int __memcmp (const void *s1, const void *s2, size_t n); extern void* __memcpy (void *s1, const void *s2, size_t n); @@ -62,7 +98,6 @@ extern long __ftell(_FILE *); extern void __rewind(_FILE *); extern size_t __fread(void *, size_t, size_t, _FILE *); extern size_t __fwrite(const void *, size_t, size_t, _FILE *); -extern int __ferror(_FILE *); extern int __fprintf(_FILE *, const char *, ...); #define DBL_MANT_DIG ( 52) diff --git a/src/libruntime/target/linux/asm_x64.h b/src/libruntime/target/linux/asm_x64.h index 59bece276..f5d72e158 100644 --- a/src/libruntime/target/linux/asm_x64.h +++ b/src/libruntime/target/linux/asm_x64.h @@ -23,10 +23,10 @@ * mov %rax -> ret */ #define SYSCALL_1( syscall_no, arg1, ret) \ - __asm ( "syscall" \ - : "=a" ( ret ) \ - : "a" (syscall_no), "D" (arg1) \ - : "rcx", "r11" ); + __asm volatile ( "syscall" \ + : "=a" ( ret ) \ + : "a" (syscall_no), "D" (arg1) \ + : "rcx", "r11" ); /* * mov syscall_no -> %rax @@ -36,10 +36,10 @@ * mov %rax -> ret */ #define SYSCALL_2( syscall_no, arg1, arg2, ret) \ - __asm ( "syscall" \ - : "=a" ( ret ) \ - : "a" (syscall_no), "D" (arg1), "S" (arg2) \ - : "rcx", "r11" ); + __asm volatile ( "syscall" \ + : "=a" ( ret ) \ + : "a" (syscall_no), "D" (arg1), "S" (arg2) \ + : "rcx", "r11" ); /* * mov syscall_no -> %rax @@ -50,10 +50,10 @@ * mov %rax -> ret */ #define SYSCALL_3( syscall_no, arg1, arg2, arg3, ret) \ - __asm ( "syscall" \ - : "=a" ( ret ) \ - : "a" (syscall_no), "D" (arg1), "S" (arg2), "d" (arg3) \ - : "rcx", "r11" ); + __asm volatile ( "syscall" \ + : "=a" ( ret ) \ + : "a" (syscall_no), "D" (arg1), "S" (arg2), "d" (arg3) \ + : "rcx", "r11" ); #define _START \ mov (%rsp), %rdi; \ diff --git a/src/libruntime/target/linux/jerry-libc.c b/src/libruntime/target/linux/jerry-libc.c index 798e96dbc..a32107de3 100644 --- a/src/libruntime/target/linux/jerry-libc.c +++ b/src/libruntime/target/linux/jerry-libc.c @@ -39,21 +39,6 @@ FIXME( Rename __unused ) #include #include -/** - * stdin file descriptor - */ -#define LIBC_STDIN 0 - -/** - * stdout file descriptor - */ -#define LIBC_STDOUT 1 - -/** - * stderr file descriptor - */ -#define LIBC_STDERR 2 - /** * Exit program with ERR_SYSCALL if syscall_ret_val is negative */ @@ -124,32 +109,11 @@ syscall_3( long int syscall_no, /**< syscall number */ return ret; } /* syscall_3 */ -/** - * printf - * - * @return number of characters printed - */ -int -__printf(const char *format, /**< format string */ - ...) /**< parameters' values */ -{ - va_list args; - - va_start( args, format); - - FIXME( Implement real printf and move it to common part of libruntime ); - long int ret = syscall_3( __NR_write, LIBC_STDOUT, (long int)format, (long int)__strlen(format)); - - va_end( args); - - return (int)ret; -} /* __printf */ - /** Output of character. Writes the character c, cast to an unsigned char, to stdout. */ int __putchar (int c) { - syscall_3( __NR_write, LIBC_STDOUT, (long int)&c, 1); + __fwrite( &c, 1, sizeof(char), LIBC_STDOUT); return c; } /* __putchar */ @@ -160,9 +124,9 @@ __putchar (int c) void __noreturn __exit (int status) /**< status code */ { - syscall_1( __NR_close, LIBC_STDIN); - syscall_1( __NR_close, LIBC_STDOUT); - syscall_1( __NR_close, LIBC_STDERR); + syscall_1( __NR_close, (long int)LIBC_STDIN); + syscall_1( __NR_close, (long int)LIBC_STDOUT); + syscall_1( __NR_close, (long int)LIBC_STDERR); syscall_1( __NR_exit_group, status); @@ -363,57 +327,20 @@ __fwrite(const void *ptr, /**< data to write */ return bytes_written; } /* __fwrite */ -/** - * fprintf - * - * @return number of characters printed - */ -int -__fprintf(_FILE *stream, /**< stream pointer */ - const char *format, /**< format string */ - ...) /**< parameters' values */ -{ - va_list args; - - va_start( args, format); - - long int ret = syscall_3( __NR_write, (long int)stream, (long int)format, (long int)__strlen(format)); - - va_end( args); - - return (int)ret; -} /* __fprintf */ - -#elif defined(LIBC_STD) || defined(LIBC_MUSL) +#elif defined(LIBC_MUSL) #include #include -/** - * printf - * - * @return number of characters printed - */ -int -__printf(const char *format, /**< format string */ - ...) /**< parameters' values */ -{ - va_list args; - - va_start( args, format); - - int ret = vprintf( format, args); - - va_end( args); - - return ret; -} /* __printf */ +const _FILE **libc_stdin = (void*)&stdin; +const _FILE **libc_stdout = (void*)&stdout; +const _FILE **libc_stderr = (void*)&stderr; /** Output of character. Writes the character c, cast to an unsigned char, to stdout. */ int __putchar (int c) { - return __printf ("%c", c); + return putchar( c); } /* __putchar */ /** exit - cause normal process termination */ @@ -519,34 +446,6 @@ __fwrite(const void *ptr, /**< data to write */ return fwrite(ptr, size, nmemb, stream); } /* __fwrite */ -/** - * ferror - */ -int -__ferror(_FILE * fp) /**< stream pointer */ -{ - return ferror( fp); -} /* __ferror */ - -/** - * fprintf - * - * @return number of characters printed - */ -int -__fprintf(_FILE *stream, /**< stream pointer */ - const char *format, /**< format string */ - ...) /**< parameters' values */ -{ - va_list args; - - va_start( args, format); - - int ret = vfprintf( stream, format, args); - - va_end( args); - - return ret; -} /* __fprintf */ - -#endif /* LIBC_STD || LIBC_MUSL */ +#else /* !LIBC_RAW && !LIBC_MUSL */ +# error "!LIBC_RAW && !LIBC_MUSL" +#endif /* !LIBC_RAW && !LIBC_MUSL */ diff --git a/src/libruntime/target/stm32f4/jerry-libc.c b/src/libruntime/target/stm32f4/jerry-libc.c index 7d0faed61..6db315cb1 100644 --- a/src/libruntime/target/stm32f4/jerry-libc.c +++ b/src/libruntime/target/stm32f4/jerry-libc.c @@ -23,36 +23,11 @@ extern void __noreturn exit(int status); -/** - * printf - * - * @return number of characters printed - */ -int -__printf(const char *format, /**< format string */ - ...) /**< parameters' values */ -{ - va_list args; - - va_start( args, format); - - /** - * TODO: Call internal vprintf implementation when it appears. - */ - int ret = 0; - - JERRY_UNIMPLEMENTED(); - - va_end( args); - - return ret; -} /* __printf */ - /** Output of character. Writes the character c, cast to an unsigned char, to stdout. */ int __putchar (int c) { - return __printf ("%c", c); + JERRY_UNIMPLEMENTED_REF_UNUSED_VARS(c); } /* __putchar */ /** exit - cause normal process termination */ @@ -65,3 +40,18 @@ __exit (int status __unused) while(true); } /* __exit */ + +/** + * fwrite + * + * @return number of bytes written + */ +size_t +__fwrite(const void *ptr, /**< data to write */ + size_t size, /**< size of elements to write */ + size_t nmemb, /**< number of elements */ + _FILE *stream) /**< stream pointer */ +{ + JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( ptr, size, nmemb, stream); +} /* __fwrite */ +