flat assembler
Message board for the users of flat assembler.

Index > Linux > Can't link 64 bit on Ubuntu

Author
Thread Post new topic Reply to topic
moveax41h



Joined: 18 Feb 2018
Posts: 59
moveax41h 19 Jul 2018, 02:36
I am trying to assemble the object file for the f64bit Hello World ELF which comes with fasm and I'm getting this:

ld first.o -dynamic-linker lc/lib/x86_64-linux-gnu/ld-linux-x86-64.so
ld: i386 architecture of input file `first.o' is incompatible with i386:x86-64 output
first.o: In function `_start':
(.text+0x1): undefined reference to `getpid'
(.text+0xc): undefined reference to `printf'
(.text+0x13): undefined reference to `_exit'

Note that I did specify the x86_64 version of ld-linux because the regular version said it was for 32 bit only. Anyone know what the problem is? This also occurs if I try to use GCC. Running Ubuntu 18.04.

This is my first time using fasm on Linux I've only used it on Windows before.

_________________
-moveax41h
Post 19 Jul 2018, 02:36
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 19 Jul 2018, 07:49
Are you sure that the object file you have is 64-bit and not a 32-bit one? What does the "format" line look like?
Post 19 Jul 2018, 07:49
View user's profile Send private message Visit poster's website Reply with quote
moveax41h



Joined: 18 Feb 2018
Posts: 59
moveax41h 19 Jul 2018, 21:26
Yes. I am trying a different file to see if I can even get anything assembled at all and I can't.. This is what happens:

Example file straight from the Linux 64-bit examples:

Code:
; fasm demonstration of writing 64-bit ELF executable
; note that linux from kernel 2.6.??? needs last segment to be writeable
; else segmentation fault is generated
; compiled with fasm 1.66

; syscall numbers: /usr/src/linux/include/asm-x86_64/unistd.h
; kernel parameters:
; r9    ; 6th param
; r8    ; 5th param
; r10   ; 4th param
; rdx   ; 3rd param
; rsi   ; 2nd param
; rdi   ; 1st param
; eax   ; syscall_number
; syscall
;
; return register:
; rax   ; 1st
; rdx   ; 2nd
;
; preserved accross function call: RBX RBP ESP R12 R13 R14 R15
;
; function parameter (when linked with external libraries):
; r9    ; 6th param
; r8    ; 5th param
; rcx   ; 4th param
; rdx   ; 3rd param
; rsi   ; 2nd param
; rdi   ; 1st param
; call library

format ELF64 executable at 0000000100000000h    ; put image over 32-bit limit

segment readable executable

entry $

        mov     edx,msg_size    ; CPU zero extends 32-bit operation to 64-bit
                                ; we can use less bytes than in case mov rdx,...
        lea     rsi,[msg]
        mov     edi,1           ; STDOUT
        mov     eax,1           ; sys_write
        syscall

        xor     edi,edi         ; exit code 0
        mov     eax,60          ; sys_exit
        syscall

segment readable writeable

msg db 'Hello 64-bit world!',0xA
msg_size = $-msg
    


What I get:

Quote:

moveax41h@moveax41h-ThinkPad-P50:~/Asm/official$ fasm a00.fasm
flat assembler version 1.73.02 (16384 kilobytes memory)
3 passes, 229 bytes.
moveax41h@moveax41h-ThinkPad-P50:~/Asm/official$ ls
a00 a00.fasm a00out
moveax41h@moveax41h-ThinkPad-P50:~/Asm/official$ gcc a00 -o a00gcc
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
moveax41h@moveax41h-ThinkPad-P50:~/Asm/official$ ld a00 -o a00out -lc --dynamic-linker /lib64/ld-linux-x86-64.so.2
ld: warning: cannot find entry symbol _start; not setting start address
moveax41h@moveax41h-ThinkPad-P50:~/Asm/official$ ./a00out
Segmentation fault (core dumped)
moveax41h@moveax41h-ThinkPad-P50:~/Asm/official$


You can see that it cannot find _start. This example file has been completely untouched, however, I tried adding in a _start, using section instead of segment, and a bunch of other stuff. It just segfaults upon run. I'm very confused.

_________________
-moveax41h
Post 19 Jul 2018, 21:26
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 19 Jul 2018, 21:42
The example you took is of creating an executable file directly. "format ELF64 executable" is like "format PE", you just run the file afterwards, no linking required.
Post 19 Jul 2018, 21:42
View user's profile Send private message Visit poster's website Reply with quote
moveax41h



Joined: 18 Feb 2018
Posts: 59
moveax41h 19 Jul 2018, 22:09
Tomasz Grysztar wrote:
The example you took is of creating an executable file directly. "format ELF64 executable" is like "format PE", you just run the file afterwards, no linking required.


Oh my God.

Holy crap.

Somebody smack me.

Thank you.

One of those moments for sure Laughing

When you know x86 assembly, but you don't know your tools well enough cuz you're new to Linux. -_-

_________________
-moveax41h
Post 19 Jul 2018, 22:09
View user's profile Send private message Reply with quote
moveax41h



Joined: 18 Feb 2018
Posts: 59
moveax41h 20 Jul 2018, 16:50
Ok so that wasn't entirely the issue. It appears as though I've been moving between different types of fasm files. So that example I used builds to ELF just fine, however, this one, fasm spits out an object file instead of an ELF for real:

Code:

; fasm example of using the C library in Unix systems

; compile the source with commands like:
;   fasm libcdemo.asm libcdemo.o
;   gcc libcdemo.o -o libcdemo
;   strip libcdemo

format ELF

include 'ccall.inc'

section '.text' executable

 public main
 extrn printf
 extrn getpid

 main:
        call    getpid
        ccall   printf, msg,eax
        ret

section '.data' writeable

 msg db "Current process ID is %d.",0xA,0
    


In fact, we see that in the comments, that is what was intended. However, I cannot link this object file:

Code:
moveax41h@moveax41h-ThinkPad-P50:/usr/share/fasm/examples/libcdemo$ ls
ccall.inc  libcdemo.asm  libcdemo.o
moveax41h@moveax41h-ThinkPad-P50:/usr/share/fasm/examples/libcdemo$ sudo gcc libcdemo.o -o libcdemo
/usr/bin/x86_64-linux-gnu-ld: i386 architecture of input file `libcdemo.o' is incompatible with i386:x86-64 output
collect2: error: ld returned 1 exit status
    


And with ld:

Code:
sudo ld libcdemo.o
ld: i386 architecture of input file `libcdemo.o' is incompatible with i386:x86-64 output
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
libcdemo.o: In function `main':
(.text+0x1): undefined reference to `getpid'
(.text+0x17): undefined reference to `printf'
    


I think this was the original problem I was having but in trying to troubleshoot it, I switched to that other one which could go directly to ELF. I'm guessing that's because the other style uses a system call instead of libc but I do want to use libc functions so I still need a hand here. Also note that this one is a 32 bit.

_________________
-moveax41h
Post 20 Jul 2018, 16:50
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 20 Jul 2018, 17:20
You should link with "-m32" switch for 32-bit and "-m64" switch for 64-bit.

gcc -m32 libcdemo.o -o libcdemo

I think that was your original problem. If you're linking with ld, then its a different story. ld requires "_start" as default entry point not "main".

or you could be missing the 32-bit libraries altogether. They're not installed by default on Ubuntu.
Post 20 Jul 2018, 17:20
View user's profile Send private message Visit poster's website Reply with quote
moveax41h



Joined: 18 Feb 2018
Posts: 59
moveax41h 20 Jul 2018, 18:54
fasmnewbie you nailed it. I simply didn't have gcc-multilib installed and installing it with apt install gcc-multilib resolved this issue, along with using the -m32.

Well, I definitely learned a lot during this process, which is cool. Don't think I've ever gotten that close to the linker itself before. Was interesting to see that it looks for _start and it totally makes sense as that's typically the "actual" entrypoint, at least when I was reverse engineering Windows binaries, there was always _start followed by a bunch of boilerplate assembly followed by a jump to "main" where the actual programmer's code began.
Post 20 Jul 2018, 18:54
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 21 Jul 2018, 20:34
Glad you solved it.

"main" is the entry point adhering to the C standard structure. It applies to all platforms that produce C executables. _start is more towards the loader and loading a process on Linux ("ld") into memory. _start marks a jump point in memory where RIP starts fetching the instructions from. It applies to all kind of objects that is to be loaded into memory not necessarily from C, since different languages may have different entry point requirements. But for C executable, it's main() because it may also contain the required command line arguments.
Post 21 Jul 2018, 20:34
View user's profile Send private message Visit poster's website Reply with quote
moveax41h



Joined: 18 Feb 2018
Posts: 59
moveax41h 22 Jul 2018, 19:18
fasmnewbie wrote:
Glad you solved it.

"main" is the entry point adhering to the C standard structure. It applies to all platforms that produce C executables. _start is more towards the loader and loading a process on Linux ("ld") into memory. _start marks a jump point in memory where RIP starts fetching the instructions from. It applies to all kind of objects that is to be loaded into memory not necessarily from C, since different languages may have different entry point requirements. But for C executable, it's main() because it may also contain the required command line arguments.


Ahh interesting. So is _start generally the address which is present in the executable file's format header as the "code entry point?" I suppose I could check with my 010 editor, but figured I'd throw that in here. I'm assuming that _start is the point where the operating system's executable file loader transfer control to the user's program after the header has been parsed and the file mapped into memory.

_________________
-moveax41h
Post 22 Jul 2018, 19:18
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2505
Furs 22 Jul 2018, 19:42
moveax41h wrote:
Ahh interesting. So is _start generally the address which is present in the executable file's format header as the "code entry point?" I suppose I could check with my 010 editor, but figured I'd throw that in here. I'm assuming that _start is the point where the operating system's executable file loader transfer control to the user's program after the header has been parsed and the file mapped into memory.
That's correct.

glibc does some stuff there, and then usually calls __libc_start_main, which ends up calling your main. There's a lot of stuff done before C's main happens.
Post 22 Jul 2018, 19:42
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 555
fasmnewbie 23 Jul 2018, 20:48
moveax41h wrote:
fasmnewbie wrote:
Glad you solved it.

"main" is the entry point adhering to the C standard structure. It applies to all platforms that produce C executables. _start is more towards the loader and loading a process on Linux ("ld") into memory. _start marks a jump point in memory where RIP starts fetching the instructions from. It applies to all kind of objects that is to be loaded into memory not necessarily from C, since different languages may have different entry point requirements. But for C executable, it's main() because it may also contain the required command line arguments.


Ahh interesting. So is _start generally the address which is present in the executable file's format header as the "code entry point?" I suppose I could check with my 010 editor, but figured I'd throw that in here. I'm assuming that _start is the point where the operating system's executable file loader transfer control to the user's program after the header has been parsed and the file mapped into memory.


Just be careful when interpreting debugging information. Different platforms may give you different preparatory code and different loaders. Windows loaders do not use "ld" when loading C executables. All C toolchain you find on Windows are emulated. IIRC, Win64 uses BaseInitThunk as its main thread loader. Loaders are really not the concern of the CPU since it is part of Operating System kernel core services or to be exact, process scheduling. CPU concerns only what appears on its RIP for fetching the next instructions.
Post 23 Jul 2018, 20:48
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.