mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
file_write_read.c: move from cpp-cheat
Improve README C section with example tree.
This commit is contained in:
36
README.adoc
36
README.adoc
@@ -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.
|
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.
|
This content makes up the bulk of the link:userland/[] directory.
|
||||||
|
|
||||||
Getting started at: <<userland-setup>>
|
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:
|
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
|
* Standard library
|
||||||
** assert.h
|
** `assert.h`
|
||||||
*** link:userland/c/assert_fail.c[]
|
*** link:userland/c/assert_fail.c[]
|
||||||
** `stdlib.h`
|
** `stdlib.h`
|
||||||
*** Exit related
|
*** exit
|
||||||
**** link:userland/c/abort.c[]
|
**** link:userland/c/abort.c[]
|
||||||
|
*** malloc
|
||||||
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 :-)
|
**** 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
|
==== 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.
|
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_scalar.S[]: see also: <<floating-point-assembly>>
|
||||||
* link:userland/arch/arm/vadd_vector.S[]: see also: <<simd-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>>
|
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_vector.S[]: see also: <<simd-assembly>>
|
||||||
* link:userland/arch/aarch64/fadd_scalar.S[]: see also: <<floating-point-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>>
|
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.
|
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>>
|
Examples at: <<simd-assembly>>
|
||||||
|
|
||||||
|
|||||||
10
lkmc.h
10
lkmc.h
@@ -4,6 +4,7 @@
|
|||||||
#define LKMC_H
|
#define LKMC_H
|
||||||
|
|
||||||
#if !defined(__ASSEMBLER__)
|
#if !defined(__ASSEMBLER__)
|
||||||
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -20,6 +21,15 @@ LKMC_ASSERT_EQ_DECLARE(32);
|
|||||||
LKMC_ASSERT_EQ_DECLARE(64);
|
LKMC_ASSERT_EQ_DECLARE(64);
|
||||||
void lkmc_assert_fail(uint32_t line);
|
void lkmc_assert_fail(uint32_t line);
|
||||||
void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, 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
|
#endif
|
||||||
|
|
||||||
/* Assert that the given branch instruction is taken. */
|
/* Assert that the given branch instruction is taken. */
|
||||||
|
|||||||
@@ -430,6 +430,7 @@ path_properties_tuples = (
|
|||||||
'exit1.c': {'exit_status': 1},
|
'exit1.c': {'exit_status': 1},
|
||||||
'exit2.c': {'exit_status': 2},
|
'exit2.c': {'exit_status': 2},
|
||||||
'false.c': {'exit_status': 1},
|
'false.c': {'exit_status': 1},
|
||||||
|
'file_write_read.c': {'baremetal': False},
|
||||||
'getchar.c': {'interactive': True},
|
'getchar.c': {'interactive': True},
|
||||||
'infinite_loop.c': {'more_than_1s': True},
|
'infinite_loop.c': {'more_than_1s': True},
|
||||||
'out_of_memory.c': {'disrupts_system': True},
|
'out_of_memory.c': {'disrupts_system': True},
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
LKMC_PROLOGUE
|
LKMC_PROLOGUE
|
||||||
mov $3, %rax
|
mov $3, %rax
|
||||||
dec %rax
|
dec %rax
|
||||||
LKMC_ASSERT_EQ_32(%rax, $2)
|
LKMC_ASSERT_EQ(%rax, $2)
|
||||||
LKMC_EPILOGUE
|
LKMC_EPILOGUE
|
||||||
|
|||||||
136
userland/c/file_write_read.c
Normal file
136
userland/c/file_write_read.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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]
|
* ./infinite_loop [period]
|
||||||
|
|||||||
Reference in New Issue
Block a user