Skip to content

Latest commit

 

History

History
618 lines (479 loc) · 29.6 KB

File metadata and controls

618 lines (479 loc) · 29.6 KB

ElfC Detailed Information

Types Supported

KeywordNameDescriptionMinimumMaximum
charCharacter8-bit unsigned0255
unsigned char
signed charSigned Character8-bit signed-128127
intSigned Integer16-bit signed-3276832767
signed int
signed
unsigned intUnsigned Integer16-bit unsigned065535
unsigned
voidVoidNo Value00
int *Pointer to Integer16-bit unsigned065535
signed int *
signed *
unsigned int *
unsigned *
char *Pointer to Character16-bit unsigned065535
unsigned char *
signed char *
void *Pointer to Void16-bit unsigned065535
int **Pointer to a Pointer to Integer16-bit unsigned065535
signed int **
signed **
unsigned int **
unsigned **
char **Pointer to a Pointer to Character16-bit unsigned065535
unsigned char **
signed char **
void **Pointer to a Pointer to Void16-bit unsigned065535
int(*)()Pointer to a Function16-bit unsigned065535

Notes:

  • Single dimension arrays of the above types are supported, such as int[] char*[], etc.
  • Function pointers are limited to one single type, int(\*)(), and they have no argument types.
  • Structures and unions composed of the above types are supported.
  • Pointers to structures and pointers to unions are supported.
  • Typedef is supported.

Type Conversions

ElfC follows the C "usual arithmetic conversions" The C Programming Language, 2nd Edition describes these rules in Section 2.7, Type Conversions, on page 42, and in Appendix A, Section A6.5 Arithmetic Conversions, on page 198. Since long, float and double types are not supported, these can be simplified as the two rules below.

  • Signed and unsigned character types are promoted to int.
  • If either of the operands are unsigned int, then (signed) int operator is promoted to unsigned.

Notes:

  • Since character types are 8-bit types that fit completely into a subset of the 16-bit int type, they will keep their signed or unsigned value when promoted.
  • A negative signed character value promotes to the same negative int value, and an unsigned charater value promotes to the same positive int value.
  • Since int types do not fit completely into the range of unsigned int types, a negative int value will promote to a large positive value.
  • A positive signed int value promotes to the same positive unsigned int value.

Examples: These examples are in the promote.c example program.

#include <stdio.h>

unsigned char uc =  77;
signed char   sc = -7;

int main() {
  char c;
  c = uc + sc;

  printf("char c = '%c' (%d)\n", c,c);
}

This program will print:

char c = 'F' (70)

The value uc promotes to int 77 and sc promotes to int -7, and 77 + (-7) = int 70, which is then assigned back to unsigned char c as 'F' or 70.

#include <stdio.h>

unsigned int  ui1 =  7;
signed int    i   = -77;

int main() {
  unsigned int ui2, ui3;

  ui2 = ui1 + i;
  printf("unsigned int ui2 = %u (%#x%)\n", ui2, ui2);
}

This program will print:

unsigned int ui2 = 65466 (0xffba)

In this example the int value -77 promotes to the unsigned int value of 65459, and 65459 plus the unigned int value 7 equals the unsigned int value of 65566.

Scope

ElfC supports declarations made in global scope and local scope.

If the declaration appears outside of any function then it is said to have global scope, which terminates at the end of the file.

If the declaration appears within a function definition or within the list of parameter declarations in a function definition, the identifier has local scope.

ElfC does not support declarations made in block scope. Declarations cannot be declared within a block defined by a pair of braces, unless that block is the definition of a function.

If an identifier is declared by declaration with local scope, then it is only available within the function where it was declared.

If an identifier is declared by declaration with global scope, then it is available throughout the file where it was declared.

Storage Class Specifiers

ElfC supports the C standard type declaration syntax as specified in ANSI C C89/C90 specification. The declaration type may be prefixed by a storage class specifier, a type qualifier or both. If both are used, the storage class specifier must come before the type qualifier.

Storage Class Specifiers
extern
static
auto
register
typedef

Notes: The auto and register storage class specifiers may only be used in local scope. ElfC will emit an error if they are used in global scope.

The register storage class specifier is treated the same as auto, except if the const type qualifier is used, then ElfC will emit an error because that combination is forbidden by the ANSI C C89/C90 specification.

The auto storage class specifier is the default for local scope declarations and static is the default for global scope declarations.

The typedef keyword is used to define user types.

Types Qualifiers

Type Qualifiers
const
volatile
const volatile
volatile const

The type qualifier volatile is accepted, and will suppress optimization.

The type qualifier const is supported for variables and pointers to constant variables.

Either volatile const or const volatile are accepted as valid syntax, and are treated exactly the same.

If a storage class specifier is used in a declaration, the type qualifier must come after it.

Per the ANSI C C89/C90 specification, register variables cannot be made constant. ElfC accepts the register keyword in a local declaration, but ignores it unless the variable is also declared const, in that case ElfC will emit an error.

Functions may be declared to return a const value. Per the ANSI C C89/C90 specification, const is ignored since a function may never be an lvalue.

Arguments to a function may be declared as const and ElfC will treat these arguments as initialized inside the function. An attempt to assign a value to a const argument inside the function is considered an error.

A pointer to an unqualified variable can be assigned to a pointer to a const or volatile variable, and vice versa.

Type qualifiers are ignored when considering if two types are compatible.

Implementation Defined Behavior

Note: This behavior is not specified by the ANSI C89/C90 specification, but may contradict behavior specified in C99 and later versions.

ElfC does not require immediate initialization in the declaration of a const variable, since ElfC does not fully support all the possible declaration type initializations.

ElfC allows variables to be declared as const and initialized later by an assignment in the code. However, a second attempt at assignment will be treated as an error.

The const keyword is supported for static (and global) arrays, and const arrays must be initialized when declared.

User defined types may include const in their typedef definition, and const may be applied to an existing user defined type.

The const keyword is ignored for structures and unions. ElfC will emit a warning message when const is ignored in these cases.

The const keyword is supported for members inside structures and unions.

ElfC does not prevent the assignment of a pointer to a const or volatile variable to an unqualified pointer.

Functions may be declared to return a volatile value and arguments may be qualified as volatile but ElfC will ignore the volatile keyword, per the ANSI C C89/C90 specification.

The volatile keyword is ignored for structures and unions. ElfC will emit a warning message when volatile is ignored in these cases.

The volatile keyword is supported for the members inside structures and unions.

User defined types may include volatile in their typedef definition, and volatile may be applied to an existing user defined type.

Differences from ANSI C89/C90

Note: The following behavior differs from the ANSI C89/C90 specification.

Neither const pointers to (varying) variables, nor const pointers to const variables are supported by ElfC, i.e. the syntaxes int * const p; and const int * const p; are not supported, and will emit an error.

The const keyword is not supported for local (auto) arrays, because ElfC does not support initializing local arrays.

Local Labels and goto

ElfC supports local labels and goto.

Local labels have functional scope and their own namespace.

The goto keyword can be used to jump directly to a local label within the same function.

There are few restrictions on local label locations and goto. For example, they may jump into the body of an iteration statement, like for or while statement, bypassing any initializations or tests done at the beginning.

ElfC will emit a warning when a local label is defined within the body of an iteration statement, but the ANSI C89/C90 specification does not prohibit this. (Jumping into an iteration statement may bypass initializations, and is considered bad practice.)

Local labels and goto should be used with caution, if used at all.

Additional Statements

The following statement and preprocessor directive were added to SubC by ElfC to support inline Asm/02 code.

  • The asm statement passes a string literal directly into the generated assembly file.

  • The #pragma preprocessor directive can be used to directly insert a line of assembly code into the generated assembly file.

Library Compiler Option

  • The new -L ElfC option will compile and assemble a C source file into a prg file defining an Elf/OS (Mini/DOS) library procedure.

  • The source file should contain a public function with same name as the file name of the C file. If no public function in the file matches the file name, an error will be generated.

  • The procedure name will be the file name with the C prefix and serve as the public entry point for the procedure function.

  • If needed, the compiler will emit an immediate jump to the public entry point function with the same name as the procedure.

  • The entry point function's public name will be suppressed to prevent duplication of the procedure name when assembling.

  • The prg produced by the assembler can then be incorporated into a library for Elf/OS or Mini/DOS.

  • The file can contain public functions and public labels. These will be available in the procedure, along with the procedure function name.

  • An Elf/OS (Mini/DOS) library is created by concatenating multiple procedure prg files.

Example:

The C file cstime.c containing the function:

static struct tm _tm;

char *cstime(void) {
  systime(&_tm);
  return asctime(&_tm);
}

When compiled with:

..\elfc -L cstime.c

Will produce the file cstime.prg that can be concatenated into an Elf/OS (Mini/DOS) library, such as time.lib. The library can then be linked to a C program to provide the cstime function.

type systime.prg asctime.prg cstime.prg > time.lib

Stdio Print Conversions

  • The flags -, +, space, 0 and # are supported.
  • The width specification is supported.
  • The suppression operator * is supported.
  • The %d, %i, %u, %o, %x, %X, %c, %s, %p, %n and %% conversions are supported.
  • The decimal precision is not supported.
  • The length modifiers h, l (el) and L are not supported.
  • The %f, %e, %E, %g and %G conversions are not supported.

Stdio Scan Conversions

  • The width specification is supported.
  • The suppression operator * is supported.
  • The %d, %i, %u, %o, %x, %c, %s, %p, %n and %% conversions are supported.
  • The charset operators %[...] and %[^...] are supported.
  • The %f, %e, and %g conversions are not supported.

When the -M option is specified, only the following conversions are supported. Using the Elfio and Elfstd libraries, reduces the binary code size by about 2K bytes.

Elfio Print Conversions (-M option)

  • Only the %d, %u, %x, %c, %s, %p, %n and %% conversions are supported.
  • The suppression operator * is supported.
  • The %i, %o, and %X conversions are not supported.
  • The flags -, +, space, 0 and # are not supported.
  • The width specification is not supported.
  • The decimal precision is not supported.
  • The length modifiers h, l (el) and L are not supported.
  • The %f, %e, %E, %g and %G conversions are not supported.

Elfio Scan Conversions (-M option)

  • The width specification is supported.
  • The suppression operator * is supported.
  • The %d, %u, %x, %c, %s, %p, %n and %% conversions are supported.
  • The %i and %o conversions are not supported.
  • The charset operators %[...] and %[^...] are not supported.
  • The %f, %e, and %g conversions are not supported.

Note: The __ELFIO__ macro is defined when the -M option is used to compile code.

Unsupported Stdlib Functions

The following functions were omitted from the ElfC stdlib C library.

  • double atof(char* s);
  • long atol(char* s);
  • double strtod(char* s, char** endp);
  • long strtol(char* s, char** endp, int base
  • unsigned long strtoul(char* s, char** endp, int base);
  • long labs(long n);
  • ldiv_t ldiv(long num, long denom);
  • int system(char *s);
  • char* getenv(char *name);

Notes:

  • All the long and double utility functions were omitted because these types are not supported in the current version.
  • The math32 library provides equivalent functions as the long utility functions.
  • The atoi32 function in math32 library provides equivalent function as atol.
  • The strtoi32 function in math32 library provides equivalent function as strtol.
  • The div32 function in math32 library provides equivalent function as ldiv.
  • The abs32 function in math32 library provides equivalent function as labs.
  • The system and genenv() functions have no equivalent functions in Elf/OS or Mini/DOS.

Unsupported Stdio Functions

The following functions were omitted from the ElfC stdio C library.

  • FILE* reopen(char* filename, char *mode, FILE* stream);
  • int setvbuf(FILE* stream, char *buf, int mode, int size);
  • int setbuf(FILE* stream, char *buf);

Note: Elf/OS and Mini/DOS use their own buffering, and do not allow streams to be reassigned.

Stdlib Modified Functions

  • Because long types are not supported, lseek takes two int arguments for the offset, and returns an int value, 0 for success or -1 for error.
  • The lseek32 function uses the int32 struct type off_tand can be used for file sizes greater than 32KB, up to 2GB.
  • itox and itou are available to convert int values to hexadecimal and unsigned integer ASCII strings.

Stdio Modified Functions

  • ftell and fseek use an int type value for position, since long type is not supported.
  • fflush is implemented as a NOP (No Operation) function.
  • tmpnam creates a filename with form similar to temp.00.
  • fclose will delete a temporary file created by tmpfile after closing it.
  • Terminating a program by abort or without calling fclose to close a temporary file, may leave behind files created by tmpfile.
  • fseek32, fgetpos and fsetposf functions use the int32 struct type pos_t and can be used for files sizes greater than 32KB, up to 2GB.

Posix String Functions

  • strcasecmp will compare two strings, ignoring case in both strings.
  • strcasestr will locate a string within another string, ignoring case in both strings.
  • strdup will allocate memory for a duplicate string, copy the characters, including the terminating null, into memory, and then return a pointer to the duplicate string.
  • strlcpy will concatenate up to a specified number (length - 1) of characters and then append a null. Unlike strncat, strlcat always appends a null.
  • strlcpy will copy up to a specified number (length - 1) of characters and then append a null. Unlike strncpy, strlcpy always appends a null.
  • strlwr will lowercase a string in place.
  • strncasecmp will compare up to n characters of two strings, ignoring case in both strings.
  • strndup will allocate memory for a string of n characters, the copy up to n characters of the original string into memory, always terminating with a null, and then return a pointer to the duplicate string.
  • strnlen will return the length of a string up to n, or n if the string is longer than n characters.
  • strnstr locate a string within the first n characters of another string.
  • strrev reverse the contents of a string in place.
  • strsep locate in a string pointed to by *str the first occurrence of any character in the separator string and replace it with a '\0'. The location of the next character after the separator is returned in *str, or NULL when the end of string is reached.
  • strupr will uppercase a string in place.
  • strim will remove any whitespace from the beginning or end of string in place.

Stdarg Macros

  • ElfC supports the variable argument macros as specified by the ANSI C C89/C90 specification.
  • The variable argument macros use an argument pointer of type va_list, eg. va_list ap;
  • The va_start should be called before va_arg is used to initialize the argument pointer.
  • The va_arg macro can then be used to get the next argument.
  • The va_end should be called after all variable arguments have been processed.
  • The argument pointer is invalid after va_end is called.
#include <stdio.h>
#include <stdarg.h>

/*
 * Function to print a number of variable arguments, specified by count
 */
int example(int count, ...) {
  int i, x;
  /* define argument pointer of type va_list */
  va_list ap;

  /* Set argument pointer to next argument after last */
  va_start(ap, count);

  /* print all the integer arguments */
  for (i=0; i < count; i++){
    /* get the next argument as integer */
    x = va_arg(ap, int);
    printf("arg %d = %d\n"i, x);
  }
  /* call va_end before function exits */
  va_end(ap);
}

Assert Macro

  • ElfC supports the assert macro as specified by the ANSI C C89/C90 specification.
  • If the macro NDEBUG is defined the assert macro is ignored.
  • The __FILE__, __LINE__ and __FUNCTION__ macros can be used as the file, line and function arguments, so the correct values are printed if the assertion is false.

Time Library

The standard C time structure tm is defined by the ElfC time C library.

struct tm {
    int tm_sec;       /* seconds after the minute (0 to 60) */
    int tm_min;       /* minutes after the hour (0 to 60) */
    int tm_hour;      /* hours after midnight (0 to 23) */
    int tm_mday;      /* day of the month (1 to 31) */
    int tm_mon;       /* months since January (0 to 11) */
    int tm_year;      /* years since 1900 */
    int tm_wday;      /* days since Sunday (0 to 6) */
    int tm_yday;      /* days since January 1 (0 to 365) */
    int tm_isdst;     /* Daylight Savings Time (0 => no, 1 => yes, -1 => unknown) */
};

Notes:

  • Many of the functions in C time library use static objects that may be over-written by other calls.

Unsupported Time Functions

The following functions were omitted from the ElfC time C library because Elf/OS v5 and Mini/DOS do not provide API for a clock or system time variable. Equivalent functions that provide the same information through a time structure are provided instead.

  • clock_t clock(void)
  • time_t void(void)
  • double difftime(time_t time2, time_t time1)
  • time_t mktime(struct tm *tp)

Local Timezone information

ElfC does not support the locale.h header, so the following function should be used to set time zone information and daylight savings time information before calling other time functions.

  • void timezone(char *tzname, int tzoff_min, int tzdst)

Notes:

  • tzname is a string abbreviation for the time zone name, such as "EST" for US Eastern Standard Time.
  • tzoff_min is the offset from Universal Co-ordinated Time in minutes. Offset values WEST of UTC should be negative, while offsets to the EAST are positive.
  • tzdst indicates if daylight savings time is in effect. It should be 1 if daylight savings time is in effect, and 0 if not.

Equivalent Time Functions

The following functions provide equivalent time functions by through a pointer to a time structure rather than through a time_t system time variable.

  • int systime(struct tm *tp) (equivalent to the localtime() function)
  • int utctime(struct tm *tp) (equivalent to the gmttime() function)
  • char *cstime(struct tm *tp) (equivalent to the ctime() function)

Notes:

  • The systime() function will populate the time structure pointed to by the tp argument with values from the OS kernel API.
  • The systime() function will use the time zone to set the tm_isdst field, or will set tm_isdst field to -1 (Unknown) if timezone() function has not been called previously.
  • The _dow() and _doy() internal time functions are used to set the tm_wday and tm_yday fields.
  • The utctime() function uses information set by the timezone() to calculate Universal Co-ordinated Time (UTC).
  • The utctime() function may not be accurate if timezone() has not be called previously.
  • The systime() and utctime() return 1 if a Real Time Clock (RTC) was used to provide the current time and 0 if data values in the kernel were used instead.
  • The cstime() function will return a pointer to a buffer with a string representing the current time.
  • The cstime() function is equivalent to calling systime() and passing the pointer with the result to asctime().

Internal Time Functions

The following internal time functions calculate the day of the week and day of the year from the fields of the time structure, and then sets the corresponding value in the time structure.

  • void _dow(struct tm *tp)
  • void _doy(struct tm *tp)

Supported Time Functions

The following functions are supported as documented.

  • char *asctime(struct tm *tp)
  • int strftime(char *s, int smax, char *fmt, struct tm *tp);

Notes:

  • asctime() provides a pointer to a buffer with a simple string representation of the time.
  • strftim() formats the date and time information pointed to by tp into a buffer s using a format string fmt that is similar to a printf format string.
  • strftime() will write up to smax characters are written into the buffer s and will return the actual number of characters written, excluding '\0'.
  • All of the ANSI (C89) strftime conversion formats are supported.

Strftime Conversions

%aabbreviated weekday name
%Afull weekday name
%babbreviated month name
%Bfull month name
%clocal date and time representation
%dday of month, as two digits with zero (01 to 31)
%FISO date representation (%Y-%m-%d)
%Hhour (24-hour clock) as two digits with zero (00 to 23)
%Ihour (12-hour clock) as two digits with zero (01 to 12)
%jday of year (001-366)
%mmonth (01 to 12)
%Mminute (00 to 59)
%PAM or PM
%pam or pm
%Ssecond (00 to 60)
%Uweek number of the year, Sunday as first day of week (00 to 53)
%wweekday (0 to 6, Sunday is 0)
%Wweek number of the year, Monday as first day of week (00 to 53)
%xlocal date representation
%Xlocal time representation
%yyear without century (00 to 99)
%Yyear with century
%Ztime zone offset in hours and minutes, as set by timezone function
%%percent sign (%)

Math32 Library

The math2 library functions use the following structure and type.

struct int32 {
    unsigned int low;   /* Lower 16 bits */
    unsigned int high;  /* Upper 16 bits */
};

/* 32-bit number represented as two 16-bit values */
typedef struct int32 int32_t;

Note: off_t in <stdlib.h> and pos_t in <stdio.h> are also defined by struct int32 typedefs.

The following functions are supported in the ElfC math32 library.

  • abs32(a) - 32-bit absolute value of a
  • add32(a, b) - 32-bit addition: returns a + b
  • sub32(a, b) - 32-bit subtraction: returns a - b
  • mul32(a, b) - 32-bit subtraction: returns a - b
  • cmp32(a, b) - Compare two 32-bit numbers, returns -1 if a < b, 0 if a == b or 1 if a > b
  • shl32(a) - Shift 32-bit number left by 1 bit
  • shr32(a) - Shift 32-bit number right by 1 bit
  • div32(a, b, *rem) - 32-bit division: returns quotient, remainder in *rem
  • to_int32(int n) - Convert 16-bit number to 32-bit number with sign extension
  • neg32(a) - Negate a 32-bit number
  • atoi32(char *str) - Convert a string into 32-bit integer
  • char *itoa32(a, char *str) - Convert 32-bit integer to string, returns pointer to beginning of string
  • strtoi32(const char *nptr, char **endptr, int base) - Convert string to 32-bit integer

Note: all variables and return values are type int32_t, unless typed differently

Pre-Defined Macros

  • If _ELFCLIB_ is defined, C code is compiled for an Elf/OS library procedure.
  • If _STGROM_ is defined, assembly code to support STG ROM breakpoints is created.
  • If _MAXMON_ is defined, assembly code to support MAXMON ROM breakpoints is created.
  • BRKPT inserts assembly code in the code file to invoke the break point handler, when _STGROM_ or _MAXMON_ is defined.
  • __LINE__ inserts the current line number in the code file.
  • __FILE__ insert the current file name in the code file.
  • __FUNCTION__ insert the current function name in the code file.
  • If NDEBUG is defined, the assert macro is ignored.
  • The <assert.h> header file defines the assert macro.
  • The <stdarg.h> header file defines the va_list type and the va_start, va_arg and va_end macros.
  • The <stdio.h> header file defines the getchar and putchar macros.
  • The <stdlib.h> header file defines the abs, MIN and MAX macros.
  • The __ELFIO__ macro is defined when the -M option is used to compile code.

Note: The __LINE__, __FILE__, __FUNCTION__ and __ELFIO__ macros begin and end with two underscores.

Unsupported Libraries

  • The setjmp library is not supported.
  • The signal library is not supported.
  • The math library is not supported, because there are no real types (float or double) in this release.

Header files

  • The float.h header file is not supported.
  • The locale.h header file is not supported.
  • The stdlib.h header file implements definitions for unistd.h, stddef.h and fcntl.h.
  • The unistd.h, stddef.h and fcntl.h header files are empty except for a single #include <stdlib.h> statement.

Compiler Options

OptionDescription
-c compile and assemble only, do not link
-d optactivate debug option OPT, ? = list
-o filewrite linker output to FILE
-t test only, generate no code
-v verbose output
-D m=vdefine macro M with optional value V
-L compile and assemble a library object file
-N do not link stdlib and stdio by default
-M use smaller elfstd and elfio libraries
-P print expanded macro text
-S compile to assembly language
-V print version and exit
Debug Options
-d gsymdump global symbols
-d lsymdump local symbols
-d statprint usage statistics
-d treedump abstract symbol tree (AST)

Details about the ElfC internal implementation can be found on the ELFC Internal Information page.