How to run a mixed language program - c

I want to write a mixed language program where part of the code will be written in C, and part of the code in assembly. I was given a sample code, so i know what should my work look like.
.globl _addArrayinA
_addArrayinA:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
movl 8(%ebp), %ebx
xorl %esi,%esi
xor %eax,%eax
bak:
addl (%ebx),%eax
addl $4,%ebx
incl %esi
cmpl $10, %esi
jne bak
movl %ebp, %esp
popl %ebp
ret
# Return value is in %ea
Above is the assembly part.
int addArrayinC(int *myArray, int num)
{
int c;
int i;
c = 0;
for (i=0; i<num; i++)
{c += *myArray;
myArray++;
}
return (c);
}
This is the second function written in C.
And below is the main file, which is supposed to use two functions above.
#include <stdio.h>
#include <stdlib.h>
extern int addArrayinC(int *numbers,int count);
extern int addArrayinA(int *numbers, int count);
int main(void) {
int mynumbers[10]={1,2,3,4,5,6,7,8,9,0};
int sum;
sum = addArrayinC(mynumbers, 10);
printf("\nThe sum of array computed in C is : %d ",sum);
sum = addArrayinA(mynumbers, 10);
printf("\nThe sum of array computed in assembly is : %d ",sum);
return EXIT_SUCCESS;
}
I tried to open these three files in codeblocks, but could not get to run them. I have no idea how to run a mixed language program. Generally, I use cloud9 for compilations of code. Anyways... How can i run code like this?

No problem here. Please note: the extension of the assembler source file has to be .s or .S(upper case if you want the file to be preprocessed e.g. for #define).

fun.c
unsigned int fun ( unsigned int x )
{
return(x+1);
}
build and examine
gcc -c -O2 fun.c -o fun.o
objdump -D fun.o
producing
0000000000000000 <fun>:
0: 8d 47 01 lea 0x1(%rdi),%eax
3: c3 retq
So we can make fun.s
.globl fun
fun:
lea 0x1(%rdi),%eax
retq
as fun.s -o fun.o
objdump -D fun.o
0000000000000000 <fun>:
0: 8d 47 01 lea 0x1(%rdi),%eax
3: c3 retq
C code so.c
#include <stdio.h>
unsigned int fun ( unsigned int x );
int main ( void )
{
printf("%u\n",fun(1));
printf("%u\n",fun(2));
printf("%u\n",fun(3));
return(0);
}
gcc lets you feed it assembly language
gcc so.c fun.s -o so
./so
2
3
4
as well as objects
gcc so.c fun.o
./so
2
3
4
so you dont have to mess with the linker directly

Related

How can I get this .c file to read a .s file and run in VS code?

I have two files, one being main.c and the other prog2.s that contains assembly code. The commands I am running are:
gcc -Wall -g -m32 -c main.c
gcc -Wall -g -m32 -c prog2.s
gcc -Wall -g -m32 -o xtest main.o prog2.o
but on that last command, I am getting an error "undefined reference to 'prog2'" twice because in main.c, I try to call prog2 twice. I tried running the main.c file without the terminal but it produced the same error.
I'm not sure code is needed but so you get an idea of what I am trying to do, here are two code samples from each of the files up until the end of the first task which is to return j-i+2.
main.c
int prog2(int i, int j, int *k, int a[5], int *l);
int main() {
int k = 6;
int l = 0, res;
int a[5] = {7, 0, 8, 0, 3};
res = prog2(6,9,&k,a,&l);
if(res != 9-6+2) {
printf("return value should be=%d; got=%d\n", 9-6+2, res);
assert(0);
}
.globl prog2
prog2:
#Setup Code
pushl %ebp
movl %esp, %ebp
pushl %ebx
# j - i + 2
movl 12(%ebp), %eax
movl 8(%ebp), %ecx
subl %ecx, %eax
addl $2, %eax

Compiling error with ld in gcc : "undefined reference to ..."

I'm on Windows 11 in 64 bit machine and for didactic purpose I'm trying to compile in 32 bit a C code (.c) with linked Assebly code (.s), with the following command:
gcc -m32 <file.c> <file.s> -o <name_file>
but the compilation failed reporting the following error:
C:\Users\david\AppData\Local\Temp\ccQPXOVR.o:e2_main.c:(.text+0x1a): undefined reference to f collect2.exe: error: ld returned 1 exit status
The MinGW version that I use is: x86_64-8.1.0-posix-sjlj-rt_v6-rev0
I think the problem is in the ld linker, because compiling the same files but in 64 bits through the following command: gcc -m64 <file.c> <file.s> -o <name_file> does not give me an error (but it is not what I need, I need to compile them in 32 bits).
Below I report the code files that I should compile
<file.c>
#include <stdio.h>
int f(int x);
int score, trials;
void test(int x, int c) {
trials++;
int r = f(x);
printf("Test %d: %d [corretto: %d]\n", trials, r, c);
score += r == c;
}
int main() {
test(3, -2);
test(4, 5);
test(7, 50);
test(17, 460);
printf("Risultato: %d/%d\n", score, trials);
return 0;
}
<file.s>
.globl f
f:
movl 4(%esp), %ecx
movl %ecx, %eax
imull $2, %eax
imull %ecx, %eax
movl $7, %edx
imull %ecx, %edx
subl %edx, %eax
incl %eax
ret
Any ideas on how I can fix it?
I would hugely appreciate any suggestions or guidance on what to do or try next, as I am a little stuck and unsure from here.
I also try to compile an other C code with -m32 flag without linking anything and it seems to have worked.
I try to install i686-8.1.0-release-posix-sjlj-rt_v6-rev0 but it doesn't seem to change anything when I compile with -m32 .

Combining c and assembler code

This is my C code:
#include <stdio.h>
void sum();
int newAlphabet;
int main(void)
{
sum();
printf("%d\n",newAlphabet);
}
And this is my assembler code:
.globl _sum
_sum:
movq $1, %rax
movq %rax, _newAlphabet
ret
I'm trying to call the sum function, from my main function, to set newAlphabet equal to 1, but when I compile it (gcc -o test assembler.c assembler.s, compiled on a 64-bit OSX laptop) I get the following errors:
32-bit absolute addressing is not supported for x86-64
cannot do signed 4 byte relocation
both caused by the line "movq %rax, _newAlphabet"
I'm sure I'm making a very basic mistake. Can anyone help? Thanks in advance.
EDIT:
Here are the relevant portions of the C code once it has been translated to assembler:
.comm _newAlphabet,4,2
...
movq _newAlphabet#GOTPCREL(%rip), %rax
Mac OS X uses position-independent executables by default, which means your code can't use constant global addresses for variables. Instead you'll need to access globals in an IP-relative way. Just change:
movq %rax, _newAlphabet
to:
mov %eax, _newAlphabet(%rip)
and you'll be set (I changed from 64 to 32 bit registers to match sizeof(int) on Mac OS X. Note that you also need a .globl _newAlphabet in there somewhere. Here's an example I just made based on your code (note that I initialized newAlphabet to prove it works):
example.c:
#include <stdio.h>
void sum(void);
int newAlphabet = 2;
int main(void)
{
printf("%d\n",newAlphabet);
sum();
printf("%d\n",newAlphabet);
return 0;
}
assembly.s:
.globl _sum
.globl _newAlphabet
_sum:
movl $1, _newAlphabet(%rip)
ret
Build & run:
$ cc -c -o example.o example.c
$ cc -c -o assembly.o assembly.s
$ cc -o example example.o assembly.o
$ ./example
2
1

Problems compiling assembly file - Error: undefined reference to `function name'

I am trying to take a look at a test program my professor gave us, but I am having trouble compiling it. I am on Ubuntu 14.04. I am compiling it with
gcc -Wall test.c AssemblyFunction.S -m32 -o test
I was having problems running the code on a 64-bit machine and read that adding -Wall and -m32 will allow it to work. Doing that fixed the first problem I had, but now I am getting the error: undefined reference to `addnumbersinAssembly'.
Here is the C file
#include <stdio.h>
#include <stdlib.h>
extern int addnumbersinAssembly(int, int);
int main(void)
{
int a, b;
int res;
a = 5;
b = 6;
// Call the assembly function to add the numbers
res = addnumbersinAssembly(a,b);
printf("\nThe sum as computed in assembly is : %d", res);
return(0);
}
And here is the assembly file
.global _addnumbersinAssembly
_addnumbersinAssembly:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp), %eax
addl 12(%ebp), %eax # Add the args
movl %ebp,%esp
popl %ebp
ret
Thank you for your time. I have been trying to figure this out for hours, so I appreciate any help.
I believe that with GCC you are going to want to remove the _ in your assembler file. So these lines:
.global _addnumbersinAssembly
_addnumbersinAssembly:
Should be:
.global addnumbersinAssembly
addnumbersinAssembly:
More information on this issue can be found in this StackOverflow question/answer.
The -m32 compile parameter is needed because the assembly code you have needs to be rewritten to support some 64 bit operations. In your case it was stack operations. The -Wall isn't needed to compile but it does turn on many more warnings.

How to hack an elf file to call other function() rather main?

I have a plain C program. I have made an executable of it. If I read an elf file, it says me that the entry point is Entry point address: 0x80482e0. After tracking the entry point, I see that the final call is the following.
080482b0 <__gmon_start__#plt-0x10>:
80482b0: ff 35 50 96 04 08 pushl 0x8049650
80482b6: ff 25 54 96 04 08 jmp *0x8049654
80482bc: 00 00 add %al,(%eax)
How can I hack the value of 0x8049654 to call some other function rather than main? I believe the main function address will be stored at the address - 0x8049654? Am I correct? What I want to do is that instead of calling main(), I want to hack it to call some other function? Is it possible?
Is the main function address should be contained in the *0x8049654 ?
main is not called from __gmon_start__:
(gdb) disassemble main
Dump of assembler code for function main:
0x080483d8 <main+0>: push %ebp // main() address
0x080483d9 <main+1>: mov %esp,%ebp
0x080483db <main+3>: and $0xfffffff0,%esp
0x080483de <main+6>: sub $0x10,%esp
0x080483e1 <main+9>: movl $0x80484c9,(%esp)
0x080483e8 <main+16>: call 0x80482f8 <puts#plt>
0x080483ed <main+21>: mov $0x0,%eax
0x080483f2 <main+26>: leave
0x080483f3 <main+27>: ret
End of assembler dump.
(gdb) disassemble __gmon_start__
Dump of assembler code for function __gmon_start__#plt:
0x080482d8 <__gmon_start__#plt+0>: jmp *0x80495c8
0x080482de <__gmon_start__#plt+6>: push $0x0
0x080482e3 <__gmon_start__#plt+11>: jmp 0x80482c8
End of assembler dump.
(gdb) # no call to main
it's got passed from the function _start:
(gdb) disassemble _start
Dump of assembler code for function _start:
0x08048310 <_start+0>: xor %ebp,%ebp
0x08048312 <_start+2>: pop %esi
0x08048313 <_start+3>: mov %esp,%ecx
0x08048315 <_start+5>: and $0xfffffff0,%esp
0x08048318 <_start+8>: push %eax
0x08048319 <_start+9>: push %esp
0x0804831a <_start+10>: push %edx
0x0804831b <_start+11>: push $0x8048400
0x08048320 <_start+16>: push $0x8048410
0x08048325 <_start+21>: push %ecx
0x08048326 <_start+22>: push %esi
0x08048327 <_start+23>: push $0x80483d8
0x0804832c <_start+28>: call 0x80482e8 <__libc_start_main#plt>
0x08048331 <_start+33>: hlt
0x08048332 <_start+34>: nop
...
You can read the ELF header and you will find the address of _start stored in e_entry:
e_entry This member gives the virtual address to which the system
first transfers control, thus starting the process. If
the file has no associated entry point, this member holds
zero.
Here a simple program to get the address:
#include <stdio.h>
#include <elf.h>
int main(int argc, char **argv) {
FILE *file;
Elf32_Ehdr hdr;
if( argc < 2 ) {
printf("uage: %s [FILE]\n", argv[0]);
return -1;
}
if( (file = fopen(argv[1], "r")) == NULL ) {
perror("Error");
return -1;
}
fread(&hdr, sizeof(Elf32_Ehdr), 1, file);
fclose(file);
if( (hdr.e_ident[EI_MAG0] != ELFMAG0) ||
(hdr.e_ident[EI_MAG1] != ELFMAG1) ||
(hdr.e_ident[EI_MAG2] != ELFMAG2) ||
(hdr.e_ident[EI_MAG3] != ELFMAG3) ) {
printf("Error: Error: Not a valid ELF file.\n");
return -1;
}
printf("Entry: 0x%.8x\n", hdr.e_entry);
return 0;
}
So if you want to redirect main to other function, you need to patch this part:
0x08048327 <_start+23>: push $0x80483d8
and replace it with your function. Here I have a simple program:
#include <stdio.h>
void function(void) {
puts("Function");
}
int main(int argc, char **argv) {
puts("Main");
return 0;
}
Will print:
$ ./prog1
Main
$
We need to figure out the address of main and function, using readelf:
$ readelf -s prog1
Symbol table '.dynsym' contains 5 entries:
...
Symbol table '.symtab' contains 66 entries:
Num: Value Size Type Bind Vis Ndx Name
...
61: 080483c4 20 FUNC GLOBAL DEFAULT 14 function
...
64: 080483d8 28 FUNC GLOBAL DEFAULT 14 main
...
$
now patch that push $0x80483d8 and replace the address of main = 080483d8 with function = 080483c4, I used a hex editor, don't forgot to flip the bytes in revere order. It will become:
0x08048327 <_start+23>: push $0x80483c4
now test it:
$ ./prog1
Function
$
Reference: How main() is executed on Linux
That was a quick and dirty way of doing it. If you just want to call something before main is called, you can make function a constructor using GCC attribute __attribute__((constructor)) like this:
#include <stdio.h>
__attribute__((constructor)) void function(void) {
puts("Function");
}
int main(int argc, char **argv) {
puts("Main");
return 0;
}
Now it will be called before main:
$ gcc -Wall prog.c -o prog
$ ./prog
Function
Main
$
Reference: Declaring Attributes of Functions
The entry point as described in your Elf file is not your main() function. main() is first as far as the C language is concerned, but the operating system has other needs (depending on the OS and the compiler). For GCC for example, your initial entry point is likely coming from assembly code in crt0.o; this code handles whatever basic initialization is required and then calls main().
While it's possible to perform a binary edit, it's certainly not trivial and assuming you have source to the code, it's highly questionable as to what benefit you would have in doing so.

Resources