file_write_read.c: move from cpp-cheat

Improve README C section with example tree.
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-06-07 00:00:03 +00:00
parent 2a27157dbf
commit 9fba97740c
6 changed files with 178 additions and 11 deletions

View File

@@ -11659,6 +11659,8 @@ One "downside" of glibc is that it exercises much more kernel functionality on i
This section contains userland content, such as <<c>>, <<cpp>> and <<posix>> examples.
Userland assembly content is located at: <<userland-assembly>>. It was split from this section basically becase we were hitting the HTML `h6` limit, stupid web :-)
This content makes up the bulk of the link:userland/[] directory.
Getting started at: <<userland-setup>>
@@ -11671,14 +11673,30 @@ This section was originally moved in here from: https://github.com/cirosantilli/
Programs under link:userland/c/[] are examples of link:https://en.wikipedia.org/wiki/ANSI_C[ANSI C] programming:
* link:userland/c/hello.c[]
* main` and environment
** link:userland/c/return0.c[]
** link:userland/c/return1.c[]
** link:userland/c/return2.c[]
** link:userland/c/exit0.c[]
** link:userland/c/exit1.c[]
** link:userland/c/exit2.c[]
** link:userland/c/print_argv.c[]
* Standard library
** assert.h
** `assert.h`
*** link:userland/c/assert_fail.c[]
** `stdlib.h`
*** Exit related
*** exit
**** link:userland/c/abort.c[]
Userland assembly content is located at: <<userland-assembly>>. It was split from this section basically becase we were hitting the HTML `h6` limit, stupid web :-)
*** malloc
**** link:userland/c/out_of_memory.c[]
** `stdio.h`
*** link:userland/c/stderr.c[]
*** link:userland/c/getchar.c[]
*** File IO
**** link:userland/c/file_write_read.c[]
* Fun
** link:userland/c/infinite_loop.c[]
==== GCC C extensions
@@ -13084,7 +13102,7 @@ Note how Sn is weirdly packed inside Dn, and Dn weirdly packed inside Qn, likely
And you can't access the higher bytes at D16 or greater with Sn.
===== ARM vadd instruction
===== ARM VADD instruction
* link:userland/arch/arm/vadd_scalar.S[]: see also: <<floating-point-assembly>>
* link:userland/arch/arm/vadd_vector.S[]: see also: <<simd-assembly>>
@@ -13203,20 +13221,20 @@ link:userland/arch/aarch64/add_vector.S[]
Good first instruction to learn SIMD: <<simd-assembly>>
===== ARMv8 aarch64 fadd instruction
===== ARMv8 aarch64 FADD instruction
* link:userland/arch/aarch64/fadd_vector.S[]: see also: <<simd-assembly>>
* link:userland/arch/aarch64/fadd_scalar.S[]: see also: <<floating-point-assembly>>
====== ARM fadd vs vadd
====== ARM FADD vs VADD
It is very confusing, but `fadds` and `faddd` in Aarch32 are <<gnu-gas-assembler-arm-unified-syntax,pre-UAL>> for `vadd.f32` and `vadd.f64` which we use in this tutorial: <<arm-vadd-instruction>>
The same goes for most ARMv7 mnemonics: `f*` is old, and `v*` is the newer better syntax.
But then, in ARMv8, they decided to use <<armv8-aarch64-fadd-instruction>> as the main floating point add name, and get rid of `vadd`!
But then, in ARMv8, they decided to use <<armv8-aarch64-fadd-instruction>> as the main floating point add name, and get rid of VADD!
Also keep in mind that fused multiply add is `fmadd`.
Also keep in mind that fused multiply add is FMADD.
Examples at: <<simd-assembly>>

10
lkmc.h
View File

@@ -4,6 +4,7 @@
#define LKMC_H
#if !defined(__ASSEMBLER__)
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
@@ -20,6 +21,15 @@ LKMC_ASSERT_EQ_DECLARE(32);
LKMC_ASSERT_EQ_DECLARE(64);
void lkmc_assert_fail(uint32_t line);
void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line);
#define LKMC_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
/* Standard action to take in case of a file IO error. */
#define LKMC_IO_ERROR(function, path) \
fprintf(stderr, "error: %s errno = %d, path = %s\n", function, errno, path); \
exit(EXIT_FAILURE);
#define LKMC_TMP_EXT ".tmp"
#define LKMC_TMP_FILE __FILE__ LKMC_TMP_EXT
#define LKMC_TMP_FILE_NAMED(name) __FILE__ "__" name LKMC_TMP_EXT
#endif
/* Assert that the given branch instruction is taken. */

View File

@@ -430,6 +430,7 @@ path_properties_tuples = (
'exit1.c': {'exit_status': 1},
'exit2.c': {'exit_status': 2},
'false.c': {'exit_status': 1},
'file_write_read.c': {'baremetal': False},
'getchar.c': {'interactive': True},
'infinite_loop.c': {'more_than_1s': True},
'out_of_memory.c': {'disrupts_system': True},

View File

@@ -5,5 +5,5 @@
LKMC_PROLOGUE
mov $3, %rax
dec %rax
LKMC_ASSERT_EQ_32(%rax, $2)
LKMC_ASSERT_EQ(%rax, $2)
LKMC_EPILOGUE

View File

@@ -0,0 +1,136 @@
#include <lkmc.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
/* Returns the size of the given open `FILE*`.
*
* If an error occurs, returns `-1L`.
*
* Does not work for pipes.
*/
long fget_file_size(FILE *fp) {
long oldpos;
long return_value;
oldpos = ftell(fp);
if (oldpos == -1L) {
return -1L;
}
if (fseek(fp, 0, SEEK_END) != 0) {
return -1L;
}
return_value = ftell(fp);
if (return_value == -1L) {
return -1L;
}
/* Restore the old position. */
if (fseek(fp, oldpos , SEEK_SET) != 0) {
return -1L;
}
return return_value;
}
/* Same as `file_size`, but takes the path instead of a `FILE*`. */
long file_size(char *path) {
FILE *fp;
long return_value;
fp = fopen(path, "r");
if (fp == NULL) {
return -1L;
}
return_value = fget_file_size(fp);
if (fclose(fp) == EOF) {
return -1L;
}
return return_value;
}
/* Read the entire file to a char[] dynamically allocated inside this function.
*
* Returns a pointer to the start of that array.
*
* In case of any error, returns NULL.
*
* http://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c
*/
char *file_read(char *path) {
FILE *fp;
char *buffer;
long fsize;
fp = fopen(path , "rb");
if (fp == NULL) {
return NULL;
}
fsize = fget_file_size(fp);
if (fsize < 0){
fprintf(stderr, "could not determine lenght of:\n%s\n", path);
return NULL;
}
buffer = (char*)malloc(fsize);
if (buffer == NULL) {
return NULL;
}
if (fread(buffer, 1, fsize, fp) != (size_t)fsize) {
return NULL;
}
if (fclose(fp) == EOF){
return NULL;
}
return buffer;
}
/* Write a null terminated string to file
*
* Return -1 on failure, 0 on success.
*/
int file_write(char *path, char *write_string) {
long len;
FILE *fp;
fp = fopen(path, "wb");
if (fp == NULL) {
return -1;
}
len = strlen(write_string);
/* copy the file into the buffer: */
if (fwrite(write_string, 1, len, fp) != (size_t)len) {
return -1;
}
if (fclose(fp) == EOF) {
return -1;
}
return 0;
}
int main(void) {
char *path = LKMC_TMP_FILE;
char *input = "asdf\nqwer\n";
/* Write entire string to file at once. */
if (file_write(path, input) == -1) {
LKMC_IO_ERROR("file_write", path);
}
/* Read entire file at once to a string. */
{
char *output = file_read(path);
if (output == NULL) {
LKMC_IO_ERROR("file_read", path);
}
assert(strcmp(input, output) == 0);
free(output);
}
/* Get file size. */
{
long size = file_size(path);
if (size == -1) {
LKMC_IO_ERROR("file_size", path);
}
assert((size_t)size == strlen(input));
}
return EXIT_SUCCESS;
}

View File

@@ -1,4 +1,6 @@
/* Loop infinitely. Print an integer whenever a period is reached:
/* https://github.com/cirosantilli/linux-kernel-module-cheat#c
*
* Loop infinitely. Print an integer whenever a period is reached:
*
* ....
* ./infinite_loop [period]