This question already has an answer here:
32-bit absolute addresses no longer allowed in x86-64 Linux?
(1 answer)
Closed 4 years ago.
with à 64 Linux system and using NASM.
I'm trying too link my ASM (hello.asm) file with a C file (main.c) and compile to a execution file.
I create a ASM file that print "Hello" with printf by using printHello function.
extern printf, exit
section .data
format db "Hello", 10, 0
section .text
global printHello
printHello:
sub rsp, 8
mov rsi, 0x12345677
mov rdi, format
xor rax, rax
call printf
mov rdi, 0
call exit
I create a simple main.c and call my function "printHello" to print "Hello"
#include <stdio.h>
void printHello();
int main()
{
printHello();
}
My command for compile :
$ nasm -f elf64 hello.asm
$ gcc -c main.c
$ gcc -o executable main.o hello.o
$ ./executable
And it prints :
./executable: Symbol `printf' causes overflow in R_X86_64_PC32 relocation
./executable: Symbol `exit' causes overflow in R_X86_64_PC32 relocation
[1] 6011 segmentation fault ./executable
I'm already learning ASM. Is the problem come from my command or my code ?
I resolved the problem by using your #Jester solution :
gcc -no-pie -o executable main.o hello.o
and thanks Ped7g for explanation.
Related
This question already has answers here:
32-bit absolute addresses no longer allowed in x86-64 Linux?
(1 answer)
How do you create jump tables in x86/x64?
(1 answer)
Assembly function address table and data under the function or in data section
(2 answers)
Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array
(1 answer)
Closed 10 months ago.
I am writing a project in x86-64 Assembly and I want to write an efficient switch statement using a branch lookup table. However, I get position independence errors.
I'll start with my code. The assembly was taken from this answer.
Assembly:
global mySwitch
section .text
mySwitch:
jmp [.jump_table + 2 * edi]
.jump_table: dw .one, .two
.one:
mov eax, 123
ret
.two:
mov eax, 321
ret
C:
#include <stdio.h>
int mySwitch(int arg);
int main() {
printf("%d\n", mySwitch(1));
}
I am trying to compile it with the following commands:
nasm -f elf64 -w+all -w+error switch.asm -o switch_asm.o
gcc -c -Wall -Wextra -std=c17 -O2 switch.c -o switch_c.o
gcc switch_asm.o switch_c.o -o switch
but the third one returns the following error:
/usr/bin/ld: switch_asm.o: relocation R_X86_64_32 against `.text' can not be used when making a PIE object; recompile with -fPIE
collect2: error: ld returned 1 exit status
make: *** [makefile:4: all] Error 1
Using the -fPIE switch is against the rules of the assignment (and also does not help), and I do not know what I am missing (previously, the problem was caused by a missing rel or wrt ..plt).
Update:
Changing my assembly code slightly to 64-bit addresses and a lea instruction like so:
lea rax, [rel .jump_table]
jmp [rax + rdi * 8]
.jump_table: dq .one, .two
compiles, and works as expected. I'd love to post this is an answer as to how to write a switch statement in asm but I cannot because this question is closed due to being a duplicate despite not being a duplicate so oh well.
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!
This question already has answers here:
x86 Linux assembler get program parameters from _start
(1 answer)
Get argv[2] address in assembler x64
(1 answer)
Closed 5 years ago.
I am trying to write a homework assignment which is to:
write a simple Assembly program that all it does is call a C program,
and send to it the command line arguments so that it may run properly
with (argc and argv).
How can this be done? We were given this asm as part of the assignment:
section .text
global _start
extern main
_start:
;;code to setup argc and argv for C program's main()
call main
mov eax,1
int 0x80
So what I want to know is, where are argc and argv located? Also, do I just need to put the pointer to argc in the eax register like when returning a value to a regular C function and the C program will work the rest out?
In the end, after compiling my C program with the following Makefile (as I said, I am new to Assembly and this is the Makefile given to us by the teacher, I do not fully understand it):
%.o: %.asm
nasm -g -O1 -f elf -o $# $<
%.o: %.c
gcc -m32 -g -nostdlib -fno-stack-protector -c -o $# $<
all: lwca
lwca: lwc.o start.o
ld -melf_i386 -o $# $^
Running ./lwca arg1 arg2 should result in argc = 3 and argv[1]=arg1 argc[2]=arg2
ANSWER:
No answer quite solved my problem, in the end the what worked was:
pop dword ecx ; ecx = argc
mov ebx,esp ; ebx = argv
push ebx ; char** argv
push ecx ; int argc
call main
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
I used to believe that we should declare a function which is defined in another file before use it, but recently I changed my way of thinking due to an experience of programming. For three files, C and ASM:
main.c
extern test_str;
/*extern myprint*/ --> If I add the line, gcc will report an error: called object ‘myprint’ is not a function
void Print_String() {
myprint("a simple test", test_str);
}
kernel.asm
extern Print_String
[section .text]
global _start
global test_str
test_str dd 14
_start:
call Print_String
jmp $
another.asm
[section .text]
global myprint
myprint:
mov edx, [esp + 8]
mov ecx, [esp + 4]
mov ebx, 1
mov eax, 4
int 0x80
ret
compile
nasm -f elf another.asm -o another.o
gcc -c -g main.c -o main.o
nasm -f elf kernel.asm -o kernel.o
ld -o final main.o kernel.o another.o
result
./final
a simple test
In my view, if I want to use the function myprint in main.c, I should declare it using extern beforehand, because myprint is defined in another file, but the result is exactly opposite. Just as main.c shows above. If I add the line extern myprint, I will get an error. However, without that declaration, I will get the right result. What's more, I didn't define function myprint in main.c, why can I use that function? Shouldn't I declare it beforehand?
When you call a function without a prototype the compiler makes some assumptions and guesses about the parameters of that function. So you should declare it, but declare it as a function:
void myprint(const char *, const char *); /* Or whatever. */
Well, you can use the function myprint, though its not defined function in main.c, with no error. This is because the compiler, while creating the object file fills in a NULL value against the symbol myprint in the object file created.
This NULL value is replaced at all places in the binary with the actual address of the function only during the linking phase. The linker refers to the symbol table across all the object files and resolves the symbol (wherever referred) with the actual address.
Certainly you shall see warnings/errors with the -Werror -Wall options to gcc. Although, you can get more insight using objdump as follows:
objdump -D main.o | less
Hope that helps to clear your doubt.