How to call external c file from assembly? - c

I'm tried this below tools, to call 2 files
My idea was to execute the function from c using assembler and create a bin file
nasm -f elf32 boot3.s -o boot3.o // convert asm file to object
gcc -c bootloader3.c -o bootloader3.o // convert c file to object
gcc boot3.o bootloader3.o -o boot3.bin // make bin file
boot3.s
section .text
bits 16
global _start ; Declare the entry point symbol
extern main ; Declare the main function as external
_start:
cli ; Disable the interrupts
call main ; Call the main function
hlt ; Halt the CPU
bootloader3.c
#include <stdio.h>
void main() {
printf("Hello, World!\n");
return;
}
My error: Error Image
Update 05.01.23
I tried to use a similar method, but with other commands, unfortunately another attempt also failed.
boot.s
bits 16
extern main
start:
cli ; Disable the interrupts
mov si, msg ; SI now points to our message
mov ah, 0x0E ; Indicate BIOS we're going to print chars
.loop lodsb ; Loads SI into AL and increments SI [next char]
or al, al ; Checks if the end of the string
jz halt ; Jump to halt if the end
int 0x10 ; Otherwise, call interrupt for printing the char
jmp .loop ; Next iteration of the loop
halt: hlt ; CPU command to halt the execution
msg: db "Hello, World!", 0 ; Our actual message to print
section .text
global puts
puts:
; Insert code for the puts function here
times 510 - ($ - $$) db 0
; Add the boot signature
dw 0xAA55
bootloader.c
//extern void puts(const char* str);
int main(void)
{
puts("Hello user");
return 0;
}
Compile using tools
First Step
nasm -f elf64 boot.s -o boot.o
gcc -c -m32 -o bootloader.o bootloader.c
ld -Ttext=0x7C00 -o boot.elf boot.o bootloader.o
Second Step
nasm -f bin boot.s -o boot.o
gcc -c -m32 -o bootloader.o bootloader.c
gcc -m32 -nostdlib -nostartfiles -Wl,-Ttext,0x7C00 boot.o bootloader.c -o boot.elf
Third Step
nasm -f elf32 boot.s -o boot.o
gcc -c -m32 -o bootloader.o bootloader.c
ld -Ttext=0x7C00 -o boot.elf boot.o bootloader.o
My Error:
On First & Third step
ld: bootloader.o:bootloader.c:(.text+0xa): undefined reference to `__main' ld: bootloader.o:bootloader.c:(.text+0x16): undefined reference to `puts'
On Seconds step
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\Klubuntu\AppData\Local\Temp\ccojaMyU.o:bootloader.c:(.text+0xa): undefined reference to `__main' c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\Klubuntu\AppData\Local\Temp\ccojaMyU.o:bootloader.c:(.text+0x16): undefined reference to `puts' collect2.exe: error: ld returned 1 exit status
Sorry for all grammar mistakes
Thanks from above help

Related

Archive has no index; run ranlib to add one (when linking with a .a containing a MachO64 object file on Linux)

I tried to create a library and test it, but an error occurred.
error code:
./libasm.a: error adding symbols: Archive has no index; run ranlib to add one
collect2: error: ld returned 1 exit status
I compiled it like this.
nasm -f macho64 ft_strlen.s -o ft_strlen.o
ar rcs libasm.a ft_strlen.o
ranlib libasm.a
gcc main.c libasm.a
Below is the source file
;ft_strlen.s
segment .text
global ft_strlen
ft_strlen:
mov rax, 0
jmp count
count:
cmp BYTE [rdi + rax], 0
je exit
inc rax
jmp count
exit:
ret
/*main.c*/
#include <stdio.h>
int ft_strlen(char *str);
int main(void)
{
char *str = "hello world";
printf("%d \n", ft_strlen(str));
}
I am using ubuntu installed on wsl.
What am I doing wrong?
Generate object files for Linux-based operating system (or perhaps more correctly, and ELF64 system) with nasm -f elf64 ft_strlen.s -o ft_strlen.o
For more info nasm -hf to see all valid output formats for nasm -f
Small tip: ranlib command is not needed because ar s is already indexing the library.

Call an assembler function from C code in linux [duplicate]

This question already has answers here:
32-bit absolute addresses no longer allowed in x86-64 Linux?
(1 answer)
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
(1 answer)
Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
(2 answers)
Closed 3 years ago.
I want to call a print function from my C program.
assembler prog:
#test.s
.text
.global _start
.global print
.type print, #function
_start:
call print
# and exit.
movl $0,%ebx # first argument: exit code.
movl $1,%eax # system call number (sys_exit).
int $0x80 # call kernel.
print:
# write our string to stdout.
movl $len,%edx # third argument: message length.
movl $msg,%ecx # second argument: pointer to message to write.
movl $1,%ebx # first argument: file handle (stdout).
movl $4,%eax # system call number (sys_write).
int $0x80 # call kernel.
mov $0, %eax
ret
.data
msg:
.ascii "Hello, world!\n" # the string to print.
len = . - msg # length of the string.
I can assemble and link it using:
$as test.s -o test.o
$ld test.o -o test
And I can execute it as a program, and it outputs "Hello, world!"
But when I tried to call a print from C code like this:
#include <stdio.h>
extern int print();
int main(){
int g;
g = print();
printf("Hello from c!, %d\n", g);
}
It was compiled using:
$gcc -c main.c test
It just prints "Hello from c, 13", that means that the function was called and return a number of chars, but does not print anything!
What am I doing wrong?
P.S.
When I trying to compile prog like this:
$as test.s -o test.o
$gcc -c main.c -o main.o
$gcc main.c test.o
I have a error:
/usr/bin/ld: test.o: in function `_start':
(.text+0x0): multiple definition of `_start'; /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/Scrt1.o:(.text+0x0): first defined here
/usr/bin/ld: test.o: relocation R_X86_64_32 against `.data' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: final link failed: nonrepresentable section on output
collect2: error: ld returned 1 exit status
Ok, done! Thanks clearlight
I can compile all use
$as test.s -o test.o
$gcc -c main.c -o main.o
$gcc -no-pie main.c test.o
And all will work fine!

The NASM has a win API but i try c link NASM an error occurred

This is NASM code, i can sure the code is normal
use golink to exe can work
GLOBAL _echoStr
EXTERN GetStdHandle, WriteConsoleA, ExitProcess
SECTION .data
msg DB "Hello World!", 13, 10, 0
msg.len EQU $ - msg
STD_OUTPUT_HANDLE EQU -11
NULL EQU 0
SECTION .bss
dummy RESD 1
SECTION .text
_echoStr:
PUSH STD_OUTPUT_HANDLE
CALL GetStdHandle
PUSH NULL
PUSH dummy
PUSH msg.len
PUSH msg
PUSH EAX
CALL WriteConsoleA
PUSH NULL
CALL ExitProcess
This is C code, i think maybe is normal
#include <windows.h>
extern void echoStr();
int main()
{
echoStr();
return 0;
}
Next, i compile NASM
nasm test.asm -f win32 -o testF.o
Next, i try compile C code and NASM obj file
gcc -o main test.c testF.o
The ERROR message is
C:\C>gcc -o main test.c testF.o
testF.o:test.asm:(.text+0x3): undefined reference to `GetStdHandle'
testF.o:test.asm:(.text+0x17): undefined reference to `WriteConsoleA'
testF.o:test.asm:(.text+0x1e): undefined reference to `ExitProcess'
collect2.exe: error: ld returned 1 exit status
I not understand ld should be link kernel32.dll
What steps have I lost?

Linking with cygwin

I have a small program that's made of an assembly function and a C function which calls it.
Now the program compiles and works perfectly on a UNIX system but when using the makefile in cygwin i get the following error:
gcc -m32 -g -c -o main.o main.c
gcc -g -m32 -o ass0 main.o myasm.o
main.o: In function main':
/cygdrive/c/ass0/main.c:15: undefined reference to_strToLeet'
collect2: error: ld returned 1 exit status
makefile:3: recipe for target 'ass0' failed
make: *** [ass0] Error 1
code of the main.c file :
#include <stdio.h>
# define MAX_LEN 100 // Maximal line size
extern int strToLeet (char*);
int main(void) {
char str_buf[MAX_LEN];
int str_len = 0;
printf("Enter a string: ");
fgets(str_buf, MAX_LEN, stdin); // Read user's command line string
str_len = strToLeet (str_buf); // Your assembly code function
printf("\nResult string:%s\nNumber of letters converted to Leet: %d\n",str_buf,str_len);
}
start of assembly code:
section .data ; data section, read-write
an: DD 0 ; this is a temporary var
section .text ; our code is always in the .text section
global strToLeet ; makes the function appear in global scope
extern printf ; tell linker that printf is defined elsewhere
strToLeet: ; functions are defined as labels
push ebp ; save Base Pointer (bp) original value
mov ebp, esp ; use base pointer to access stack contents
pushad ; push all variables onto stack
mov ecx, dword [ebp+8] ; get function argument
makefile code :
all: ass0
ass0: main.o myasm.o
gcc -g -m32 -o ass0 main.o myasm.o
main.o: main.c
gcc -m32 -g -c -o main.o main.c
myasm.o: myasm.s
nasm -g -f elf -l ass0list -o myasm.o myasm.s
help would be most appriciated
Solved by user 'tvin' -
Try to modify your prototype to become extern int strToLeet (char*) asm ("strToLeet"); – tivn

GNU Linker and architecture i386

So I'm running on OS X and I want to link two Mach-O objects i386.
The first is generated from NASM (it's an assembly file)
nasm -f macho -o kernel.o kernel.asm
The second is generated from GCC
gcc -c -arch i386 screen.c
But when I try to link them...
ld -o myprogram screen.o kernel.o
...I get this error :
Undefined symbols for architecture i386:
"print", referenced from:
start in kernel.o
ld: symbol(s) not found for inferred architecture i386
I don't understand why, because my two files are Mach-O object i386 :
$ file screen.o
screen.o: Mach-O object i386
$ file kernel.o
kernel.o: Mach-O object i386
If you need it, here's kernel.asm :
[BITS 32]
EXTERN print
GLOBAL start
start:
mov eax, msg
push eax
call print
pop eax
end:
jmp end
msg db 'Hello world!', 10, 0
And here's screen.c :
void putcar(uchar c)
{
/* Some code here */
}
void print(char *string)
{
while(*string != 0){
putcar(*string);
string++;
}
}
You need to use the symbol _print in your asm file, i.e.
start:
mov eax, msg
push eax
call _print
pop eax
This is because C function names get a leading underscore when compiled.

Resources