asm compilation C - c

I have a small program in C that uses the asm() function to use assembly instructions. However, at the time of compilation, it gives me a link error that I can't correct. Indeed as the use of -m32 is necessary in order to use the instruction 'move' I think that it is wrong 'lib' to use.
main.c:
#include <stdio.h>
#include "myJump.h"
static struct ctx_s pctx_buf;
int main() {
int prod1;
prod1 = mul(0);
printf("prod1 = %d\n", prod1);
int prod2;
prod2 = tryIt(&pctx_buf, shintMule, 0);
printf("prod2 = %d\n", prod2);
}
myJump.c:
#include "myJump.h"
#include <stdio.h>
#include <assert.h>
#define CTXMAGIC 0x73478336
static int thr;
static struct ctx_s pctx_buf;
int mul(int d) {
int i;
switch (scanf("%d", &i)) {
case EOF:
return 1;
case 0:
return mul(d + 1);
case 1:
if (i) {
return i * mul(d + 1);
} else {
return 0;
}
}
return 0;
}
int tryIt(struct ctx_s *pctx, funct_t *f, int arg) {
copyBuf(*pctx);
asm("movl %0, %%esp"
:
:"r"(pctx->ctx_esp));
asm("movl %0, %%ebp"
:
:"r"(pctx->ctx_ebp));
pctx->ctx_magic = CTXMAGIC;
return f(arg);
}
void copyBuf(struct ctx_s pctx){
pctx_buf.ctx_ebp = pctx.ctx_ebp;
pctx_buf.ctx_esp = pctx.ctx_esp;
pctx_buf.ctx_magic = pctx.ctx_magic;
}
int throwIt(struct ctx_s *pctx, int r) {
assert( pctx->ctx_magic == CTXMAGIC );
thr = r;
asm("movl %%esp, %0"
:"=r"(pctx->ctx_esp));
asm("movl %%ebp, %0"
:"=r"(pctx->ctx_ebp));
return thr;
}
int shintMule(int d) {
int i;
switch (scanf("%d", &i)) {
case EOF:
return 1;
case 0:
return mul(d + 1);
case 1:
if (i) {
return i * mul(d + 1);
} else {
throwIt(&pctx_buf, 0);
}
}
}
MAKEFILE:
all : main
main : main.o myJump
main.o : main.c myJump.h
gcc -c -O2 -Wall -march='x86-64' main.c
myJump : myJump.o
myJump.o : myJump.c myJump.h
gcc -c -O2 -Wall -march='x86-64' -m32 myJump.c
clean :
rm *.o main
The error after make all:
gcc -c -O2 -Wall -march='x86-64' main.c
gcc -c -O2 -Wall -march='x86-64' -m32 myJump.c
cc myJump.o -o myJump
/usr/bin/ld : architecture i386 du fichier d'entrée « %B » est incompatible avec la sortie ЛZV�U
/usr/bin/ld : /usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/Scrt1.o : dans la fonction « _start » :
(.text+0x20) : référence indéfinie vers « main »
collect2: error: ld returned 1 exit status
make: *** [<commande interne> : myJump] Erreur 1
EDIT1: pass to 64bits
main.c:
the printf it's for debug
#include <stdio.h>
#include "myJump.h"
int main() {
int prod1;
prod1 = mul(0);
printf("prod1 = %d\n", prod1);
printf("0");
struct ctx_s pctx_buf;
int prod2;
printf("1");
prod2 = tryIt(&pctx_buf, shintMule, 0);
printf("10");
printf("prod2 = %d\n", prod2);
}
myJump.c:
#include "myJump.h"
#include <stdio.h>
#include <assert.h>
#define CTXMAGIC 0xDEADBEAF
static int thr;
static struct ctx_s pctx_buf;
int mul(int d) {
int i;
switch (scanf("%d", &i)) {
case EOF:
return 1;
case 0:
return mul(d + 1);
case 1:
if (i) {
return i * mul(d + 1);
} else {
return 0;
}
}
return 0;
}
int tryIt(struct ctx_s *pctx, funct_t *f, int arg) {
copyBuf(*pctx);
asm("mov %0, %%rsp"
:
:"r"(pctx->ctx_rsp));
asm("mov %0, %%rbp"
:
:"r"(pctx->ctx_rbp));
pctx->ctx_magic = CTXMAGIC;
return f(arg);
}
void copyBuf(struct ctx_s pctx){
pctx_buf.ctx_rbp = pctx.ctx_rbp;
pctx_buf.ctx_rsp = pctx.ctx_rsp;
pctx_buf.ctx_magic = pctx.ctx_magic;
}
int throwIt(struct ctx_s *pctx, int r) {
assert( pctx->ctx_magic == CTXMAGIC );
thr = r;
asm("mov %%rsp, %0"
:"=r"(pctx->ctx_rsp));
asm("mov %%rbp, %0"
:"=r"(pctx->ctx_rbp));
return thr;
}
int shintMule(int d) {
int i;
switch (scanf("%d", &i)) {
case EOF:
return 1;
case 0:
return mul(d + 1);
case 1:
if (i) {
return i * mul(d + 1);
} else {
throwIt(&pctx_buf, 0);
}
}
return 0;
}

Related

String Corruption in my Number Printing Function for 16bit Real Mode DOS

I'm writing a program that will run in 16bit real-mode in DOS, compiling with GCC, and testing under DOSBox.
This is the linker script I am using to create the executable (coped from https://github.com/skeeto/dosdefender-ld31/blob/master/com.ld):
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0x0100;
.text :
{
*(.text);
}
.data :
{
*(.data);
*(.bss);
*(.rodata);
}
_heap = ALIGN(4);
}
I can print strings terminated with a '$', but cannot with a 2 character string containing a digit and a '$'; I get a memory dump as you can see below:
Here's my makefile, I pass flags to gcc minimize size, and not to link to a C runtime library.
CC = gcc
DOS = dosbox
CFLAGS = -std=gnu99 -Wall -Wextra -Os -nostdlib -m32 -march=i386 \
-Wno-unused-function \
-ffreestanding -fomit-frame-pointer -fwrapv -fno-strict-aliasing \
-fno-leading-underscore -fno-pic -fno-stack-protector \
-Wl,--nmagic,-static,-Tcom.ld,--verbose=99
.PHONY : all clean test
all:
$(CC) -o bottles.com $(CFLAGS) main.c
clean :
$(RM) *.com
test : bottles.com
$(DOS) $^
%.com : %.c
$(CC) -o $# $(CFLAGS) $<
Here is 'main.c':
asm (".code16gcc\n"
"call dosmain\n"
"mov $0x4C,%ah\n"
"int $0x21\n");
static void print(char *string)
{
asm volatile ("mov $0x09, %%ah\n"
"int $0x21\n"
: /* no output */
: "d"(string)
: "ah");
}
static int _pow(int a, int b)
{
int x = a;
for (int i=1; i < b; i++) {
x = x * a;
}
return x;
}
static int getdigits(int val)
{
int d = 0;
int n = val;
while (n != 0) {
n /= 10;
d++;
}
return d;
}
static void putint(int val)
{
const int digits_num = getdigits(val);
const int base10_m = _pow(10, (digits_num - 1));
int r = val;
const char eof = '$';
char digit_s[2] = {0,eof};
for (int i = base10_m; i >= 10 ; i/=10) {
digit_s[0] = '0' + ( r - ( r % i ) ) / i ;
print(digit_s);
r -= ( r - ( r % i ));
}
digit_s[0] = '0' + r;
print(digit_s);
}
int dosmain(void)
{
print(1337);
return 0;
}
What is causing the memory to be dumped as shown above?
I solved my problem by looking at this page: http://spike.scu.edu.au/~barry/interrupts.html#ah02.
On the page there's another interrupt function, 0x02, which prints out a character pushed to the stack.
I wrote this function to call this interrupt function:
static void putchar(char ch)
{
asm volatile ("mov $0x02, %%ah\n"
"int $0x21\n"
: /* no output */
: "d"(ch)
: "ah");
}
And sure enough, it works:

Undefined function reference in C

I've several files with main functions in C, for example, I've files called show.c, delete.c add.c (...). I also have a file, called interpreter.c, which may call one of the files, for example delete.c. Most of these file implement a main function, like the delete.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int main (int argc, char *argv[])
{
int fd, rm;
char *caminho = argv[1]; // argumento inserido no terminal
char caminhod[30]="../TPSOFinal/";
strcat(caminhod,argv[1]);
fd = open(caminhod, O_RDONLY);
rm=unlink(caminhod);
// Verifica se o caminho inserido no input existe
if(rm == 0){
write(1,"Ficheiro eliminado!!!\n", 22);
return 0;
}
else{
write(1,"Erro ao eliminar ficheiro !!!\n", 29);
perror("Erro");
}
return 0;
close(fd);
}
The interpreter:
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>
#define LER_BUFFER 1024
#define TBUFF 64
#define DELIM "\t\r\n\a"
int mostra(char **args);
int conta(char **args);
int acrescenta(char **args);
int apaga(char **args);
int informa(char **args);
int lista(char **args);
int manual(char **args);
int termina(char **args);
char *comando[] =
{
"mostra <caminho>",
"conta <caminho>",
"acrescenta <caminho> <caminho destino>",
"apaga <caminho>",
"informa <caminho>",
"lista <caminho>",
"manual",
"termina",
" ",
};
int (*fcomandos[]) (char**) =
{
&mostra,
&conta,
&acrescenta,
&apaga,
&informa,
&lista,
&manual,
&termina
};
int ncomandos()
{
return sizeof(comando)/sizeof(char*);
}
void processa(char *linha, char **argv)
{
while(*linha != '\0')
{
while(*linha == ' ' || *linha == '\t' || *linha == '\n')
{
*linha++ = '\0'; //troca caracteres especiais
}
*argv++ = linha; //guarda posição
while (*linha != '\0' && *linha != ' ' && *linha != '\t' && *linha != '\n')
{
linha++;
}
}
*argv = NULL;
}
char *lerlinha (void)
{
char *linha = NULL;
ssize_t tam = 0;
getline (&linha, &tam, stdin);
return linha;
}
char **separa (char *linha)
{
int tam = TBUFF, pos = 0;
char **palavras = malloc (tam *sizeof(char*));
char *palavra;
if (!palavras)
{
perror("Erro");
exit(EXIT_FAILURE);
}
palavra = strtok (linha, DELIM);
while (palavra != NULL)
{
palavras [pos] = palavra;
pos ++;
if (pos >= tam)
{
perror ("Erro");
}
}
palavra = strtok(NULL, DELIM);
palavras [pos] = NULL;
return palavras;
}
int launch (char **args)
{
pid_t pid, wpid;
int estado;
pid = fork();
if (pid == 0)
{
if(execvp(args[0],args)==-1){ perror ("Erro!"); }
exit (EXIT_FAILURE);
}
if (pid <0)
{
perror ("Erro!");
}
else
{
do{wpid = waitpid(pid, &estado, WUNTRACED);}
while (!WIFEXITED(estado)&& !WIFSIGNALED(estado));
}
return 1;
}
//Testa se os comandos existem
int mostra (char **args)
{
if (args[1] == NULL)
{
perror("sem argumentos ");
}
else if (chdir (args[1]) != 0)
{
perror ("Erro!");
}
return 1;
}
int conta ( char ** args)
{
if (args[1] == NULL)
{
perror("Sem argumentos ");
}
else if (chdir (args[1])!= 0)
{
perror ("Erro!");
}
return 1;
}
// Manual dos comandos
int manual (char **args)
{
int i;
printf("\n\nMiguel Oliveira\n");
printf("10260 - LESI\n");
printf("Sistemas Operativos e Sistemas Distribuidos\n");
printf("\nLista de Comandos\n");
for (i=0; i<ncomandos(); i++)
{
printf("%s\n", comando[i]);
}
return 1;
}
int termina (char **args)
{
return 0;
}
//Executa os comandos
int executar (char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i=0; i<ncomandos(); i++)
{
if (strcmp(args[0], comando[i])==0)
{
return (*fcomandos[i])(args);
}
}
return launch(args);
}
//Interpretador
void interpretador (void)
{
char *linha;
char **args;
int estado;
do
{
printf("%% ");
linha = lerlinha();
args = separa(linha);
estado = executar(args);
free(linha);
free(args);
} while (estado);
}
int main (void)
{
interpretador();
return EXIT_SUCCESS;
}
I've tried to research for similar problems, and i've found some little possible solutions, but cannot solve my problem, as show on bottom GCC compile mistake
You do not "call source files"; source files define functions and variables, and when compiled, ones defined in different files can use each other if they have a declaration (in a header file, usually) or a pointer (via dynamic link methods, like POSIX dlsym()).
Consider this minimal example. First, example.c:
#include <stdlib.h>
#include <stdio.h>
/* We expect someone else to define these */
extern int one(void);
int main(void)
{
printf("one() returned %d.\n", one());
return EXIT_SUCCESS;
}
and helper.c:
int one(void)
{
return 2; /* TODO: It's not one! */
}
You compile each source file to an object file:
gcc -Wall -O2 -c example.c
gcc -Wall -O2 -c helper.c
and then you link them to an executable program:
gcc -Wall -O2 example.o helper.o -o program
which you can run using
./program
Normally, each C source file that provides functions or variables usable outside that file, declares them in a header file. Here's a better example.
degrees.h
#ifndef DEGREES_H
#define DEGREES_H
double radians_to_degrees(double);
double degrees_to_radians(double);
#endif /* DEGREES_H */
The #ifndef, #define, and #endif are used as guards, so that if you #include the file more than once, the functions get declared only once. (The compiler will complain if it sees multiple declarations. Plus, we don't need to use extern here.)
The implementation of the above is then in degrees.c,
#ifndef PI
#define PI 3.14159265358979323846
#endif
double degrees_to_radians(double degrees)
{
return degrees * PI / 180.0;
}
double radians_to_degrees(double radians)
{
return radians * 180.0 / PI;
}
In a program myprog.c in the same project, you would use the above thus:
#include <stdlib.h>
#include <stdio.h>
#include "degrees.h"
int main(void)
{
printf("45 degrees is %.6f radians.\n", degrees_to_radians(45.0));
printf("2 radians is %.3f degrees.\n", radians_to_degrees(2.0));
return EXIT_SUCCESS;
}
and again you'd compile first the two source files to object files,
gcc -Wall -O2 -c degrees.c
gcc -Wall -O2 -c myprog.c
and then link together to a program, say myprog,
gcc -Wall -O2 degrees.o myprog.o -o myprog
which you can then run:
./myprog
It is also possible to compile and link the functions and variables declared in degrees.h to a static (libdegrees.a) or a dynamic (libdegrees.so) library, and install the header file to the standard location, so that your program could instead use #include <degrees.h> and the program link to the library via -ldegrees, but that is better left until you are well comfortable working with multiple files.
Until then, you might find the following Makefile useful
CC := gcc
CFLAGS := -Wall -O2
LDFLAGS :=
PROGS := myprog
all: clean $(PROGS)
clean:
rm -f *.o $(PROGS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
myprog: degrees.o myprog.o
$(CC) $(CFLAGS) $^ -o $#
You can add multiple programs in the PROGS line, separated by spaces, and copy the myprog: lines for each, listing the object files that program needs.
With this, all you need to compile the program is to type make.
This forum eats Tabs, and Makefiles need indentation to use those. So, if you just copy-paste that to a file, it won't work. You can fix it, though, by running
sed -e 's|^ *|\t|' -i Makefile
which removes all initial spaces on each line with a tab in file Makefile.
If you use separate libraries, typically libm (#include <math.h>), you just need to add -lm (dash ell em) to the LDFLAGS line. If you eventually play with dynamic linking, that's -ldl.
If you were to write a graphical program using Gtk+, you'd append `pkg-config --cflags gtk+-3.0` (including the backticks `) to the CFLAGS line, and `pkg-config --libs gtk+-3.0` to the LDFLAGS line, and #include <gtk/gtk.h> to your program.

Using Dynamic library Load returns another result

i have an issue using DLL, i have a code that encrypt strings, buf using dll the result of the function changes.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cantidad(char *s){
int max=0;
for (int i = 0; s[i] ; i++) {
max=i;
}
return max+1;
}
char* pascal(char *s) {
//char s1[cantidad(s)];
int cuociente;
char *s1=calloc(strlen(s)+1,sizeof(char));
strcpy(s1,s);
if (s == NULL){ //caso que sea nulo.
return NULL;
}
cuociente=cantidad(s)/2;
if(cantidad(s)%2==0){//par
for (int i = 0; i <cuociente-1 ; i++) {
if(i%2==0){ // iteracion impar debido a que esta parte siendo iteracion 1,
s[cuociente-2-i]=s1[cantidad(s)-1-i];
s[cuociente+1+i]=s1[i];
}
if(i%2!=0){// iteracion par
s[cuociente-2-i]=s1[i];
s[cuociente+1+i]=s1[cantidad(s)-1-i];
}
}
}
if(cantidad(s)%2!=0){//impar
for (int k = 0; k <cuociente-1 ; k++) {
if (k%2==0){ //iteracion impar
s[cuociente-2-k]=s1[cantidad(s)-1-k];
s[cuociente+2+k]=s1[k];
}
if (k%2!=0){ //iteracion par
s[cuociente-2-k]=s1[k];
s[cuociente+2+k]=s1[cantidad(s)-1-k];
}
}
}
printf("%s",s);
return s;
}
Using CLion and terminal, if i encrypt "btvenyz tnyvn" the function returns "teytnyz bvvnn" that its the expected result.
But if i use makefile and DLL:
MAKEFILE:
all: shared compile
shared:
gcc -c -Wall -Werror -fpic ./lib/pascal.c
mkdir ./sym
gcc -shared -o ./sym/libpascal.so pascal.o
compile:
mkdir ./bin
gcc -Wall -Werror main.c -o ./bin/hash -ldl
rm -r *.o
clean:
rm -r ./sym ./bin
MAIN WITH DLL:
int main(){
char palabra[256],seq[256];
char (*func_pascal)(char[]);
void *handle_pascal;
char *error;
//PREPARE LIBRARY
handle_pascal= dlopen("../sym/libpascal.so",RTLD_LAZY);
// ERROR
if(!handle_pascal){
fprintf(stderr, "%s \n", dlerror());
exit(EXIT_FAILURE);
}
dlerror();
func_pascal = (char (*)(char[])) dlsym(handle_pascal,"pascal");
error = dlerror();
//ERROR
if(error != NULL){
fprintf(stderr,"%s \n", error);
exit(EXIT_FAILURE);
}
//INPUT
fgets(palabra,256,stdin);
fgets(seq,256,stdin);
printf("STRING: %s\n",palabra);
for (int i = 0; seq[i]; ++i)
{
if (seq[i]=='P')
{
(*func_pascal)(palabra);
printf("ENCRYPTED WORD:%s\n",palabra);
}
}
return 0;
}
Using DLL the output is:
INPUT
btvenyz tnyvn
P
OUTPUT
STRING: btvenyz tnyvn
ynevt
z bnvyntENCRYPTED WORD:ynevt
z bnvynt
Originally there are several encryption codes, where only this one generates error in the output, so I would like to know what I am doing wrong and how to solve it, thank you very much!

MINIX 2 - syscall to kernel

I want to make 2 syscalls to kernel (getlot and setlot). They have to read and set some value in struct proc, which is in kernel. What is the problem? What is missing?
In /usr/include/minix/callnr.h I increased NCALLS and add 2 define
#define NCALLS 80 /* number of system calls allowed */
#define SETLOT 78
#define GETLOT 79
In usr/src/mm/main.c
PUBLIC void do_setlot()
{
message msg;
msg = mm_in;
_taskcall(SYSTASK, SYS_SETLOT), &msg);
}
PUBLIC void do_getlot()
{
message msg;
msg = mm_in;
_taskcall(SYSTASK, SYS_GETLOT, &msg);
}
In /usr/src/mm/proto.h I added two prototypes
_PROTOTYPE( void do_setlot, (void));
_PROTOTYPE( void do_getlot, (void));
In /usr/src/mm/table.c I added to the end of _PROTOTYPE (int (*call_vec[NCALLS]), (void) )
do_setlot,
do_getlot,
In /usr/src/fs/table.c I added to the end of_PROTOTYPE (int (*call_vec[]), (void) )
no_sys,
no_sys,
In /usr/include/minix/com.h I created 2 SYS_xxx define
# define SYS_SETLOT 22
# define SYS_GETLOT 23
In /usr/src/kernel/system.c I wrote
FORWARD _PROTOTYPE( int do_procsetlot, (message *m_ptr) );
FORWARD _PROTOTYPE( int do_procgetlot, (message *m_ptr) );
Then added SYS_xxx to switch in PUBLIC void sys_task()
case SYS_SETLOT: r = do_procsetlot(&m); break;
case SYS_GETLOT: r = do_procgetlot(&m); break;
And at the bottom I wrote 2 definions
PRIVATE int do_procsetlot(m_ptr)
register message *m_ptr;
{
pid_t prid;
int i;
int tickets;
prid = m_ptr->m1_i1;
tickets = m_ptr->m1_i2;
if(tickets > LOT_MAX)
return EINVAL;
if(tickets < LOT_MIN)
return EINVAL;
for(i = 0 ; i <NR_PROCS; i++)
{
if(proc[i].p_pid == prid)
{
proc[i].tickets_number = tickets;
return 0;
}
{
return EINVAL;
}
PRIVATE int do_procgetlot(m_ptr)
register message *m_ptr;
{
int i;
pid_t prid;
prid = m_ptr->m1_i1;
for(i = 0 ; i< NR_PROCS; i++)
{
if(proc[i].p_pid == prid)
return proc[i].tickets_number;
}
return EINVAL;
}
Finally after make hdboot I got error:
exec cc -c -I/usr/include main.c
exec cc -c -I/usr/include proc.c
exec cc -c -I/usr/include system.c
"system.c", line 1260: static not expected
make in /usr/src/kernel: Exit code 1
Line 1260 is
PRIVATE int do_procgetlot(m_ptr)
I know this message is years old, but...
You have a syntax error at the bottom of do_procsetlot:
{
return EINVAL;
}
...should be:
}
return EINVAL;
}
I hope you figured it out yourself some time in 2014!
BTW, the Minix 2 compiler totally supports ANSI C, so you shouldn't need all the K&Risms.

using structure result in one file into another file?

I have two files: p1.c and p2.c.
I need to use the value stored in the structure in p1.c into p2.c. Please help me figure out how to achieve this. Should I use extern?
p1.c
typedef struct What_if
{
char price[2];
} what_if ;
int main()
{
what_if what_if_var[100];
file * infile;
infile=fopen("filepath");
format_input_records();
}
int format_input_records()
{
if ( infile != NULL )
{
char mem_buf [500];
while ( fgets ( mem_buf, sizeof mem_buf, infile ) != NULL )
{
item = strtok(mem_buf,delims);
strcpy(what_if_var[line_count].price,item) ;
printf("\ntrans_Indicator ==== : : %s",what_if_var[0].price);
}
}
}
p2.c
"what_if.h" // here i include the structure
int main()
{
process_input_records(what_if_var);
}
int process_input_records(what_if *what_if_var)
{
printf("\nfund_price process_input_records ==== : : %s",what_if_var[0]->price);
return 0;
}
Try this:
whatif.h:
#ifndef H_WHATIF_INCLUDED
#define H_WHATIF_INCLUDED
struct whatif {
char price[2];
};
int wi_process(struct whatif *);
#endif
p1.c
#include "whatif.h"
int main(void) {
struct whatif whatif[100];
whatif[0].price[0] = 0;
whatif[0].price[1] = 1;
whatif[1].price[0] = 42;
whatif[1].price[1] = 74;
whatif[99].price[0] = 99;
whatif[99].price[1] = 100;
wi_process(whatif);
return 0;
}
p2.c
#include <stdio.h>
#include "whatif.h"
int wi_process(struct whatif *arr) {
printf("%d => %d\n", arr[0].price[0], arr[0].price[1]);
printf("%d => %d\n", arr[1].price[0], arr[1].price[1]);
printf("%d => %d\n", arr[99].price[0], arr[99].price[1]);
return 3;
}
Then compile and link all of them together, for example with gcc
gcc -ansi -pedantic -Wall p1.c p2.c

Resources