Static linkage with glibc without calling main - gcc

I have created a simple hello world using NASM which calls printf and _exit from libc but does not use main.
extern printf
extern _exit
section .data
hello: db 'Hello world!',10
section .text
global _start
_start:
xor eax, eax
mov edi, hello
call printf
mov rax, 0
jmp _exit
I create the object file like this
nasm -felf64 hello.asm
Then I can link it using dynamic linkage with glibc like this
ld hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -melf_x86_64
This runs correctly with no errors. But now I want to do it statically. I do
ln -s `gcc -print-file-name=libc.a`
ln -s `gcc -print-file-name=libgcc_eh.a`
ld hello.o -static libc.a libgcc_eh.a libc.a -melf_x86_64
This links but when I run the code I get a segmentation fault. Using gdb I see it gives
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401004 in vfprintf ()
If I write a simple hello world in C and compile with static in runs fine so apparently it's possible to link statically to glibc on my system. How can I use static linkage with glibc with my assembly code?
If I link to an alternative to glibc such as musl-libc it works fine
ld hello.o -static /usr/local/musl/lib/libc.a -melf_x86_64
I'm using Ubuntu 14.04, eglibc 2.19, and GCC 4.9.1

Glibc have a huge initialization sequence, because it is done with strong intention to work in multithreading systems. Also GLIBC properly handles some GNU extensions like constructor attributes. On startup, it caching a lot inside TLS, including locale information, it initializes synchronization objects and so on.
Exact problem with your vprintf is uninitialized locale access.
When you are linking to it dynamically, all this work is done on loading and everything works.
Statically linked glibc requires __libc_init_first to be called to initialize all it need. Before this call you need __dl_tls_setup to properly setup TLS and after this call you will need __libc_csu_init to properly call all global constructors.
All this stuff is highly version-dependent and practically undocumented. Strictly saying, there is no safe way to link statically to glibc, skipping or modifying its normal _start sequence.
On the other hand, embedded-oriented libraries like musl or newlib are not so restrictive about initialization and multithreading and locales.

Related

Compiling error whilst using command from NASM and mingw

I want to play a bit with assembly. To get started I've created a little asm script and tried to compile it. In the first step everything went great:
nasm -felf64 hello.asm
But when I tried to use
ld -o hello.o hello
from MinGW an error occured:
hello.o: file not recognized: File format not recognized
What can I do to fix this problem? I've tried it with gcc as well but then the same error plus one other error occurs.
MinGW creates binaries targeting Windows. Windows does not support ELF binaries (or does it? with Windows subsystem for Linux?). Anyway, ld in MinGW will expect that you provide binaries in win64 format not elf64.
nasm -fwin64 hello.asm will most likely work.
No it won't work because I just saw your code, and you are using Linux syscalls under Windows.
Write,
mov rcx, 69
call ExitProcess
instead of,
mov rax, SYS_EXIT
mov rdi, 69
syscall
Leave a comment if it doesn't work.

GNU Assembler in Windows Subsystem for Linux fail

I would like to compile "Hello World" in Windows Subsystem for Linux (WLS) with Debian.
.text
.global _start
_start:
movl $len,%edx
movl $msg,%ecx
movl $1,%ebx
movl $4,%eax
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
.data
msg:
.ascii "Hello, world!\n"
len = . - msg
If i compile in a Debian server with
gcc -nostdlib -o hello hello.s
It work, but in WLS return error
/usr/bin/ld: /tmp/cciVVddg.o: relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output collect2: error: ld returned 1 exit status
I also tried
gcc -fPIC -nostdlib -o hello hello.s
There are two problems with your code:
your code is intended to be 32 bit code but gcc tries to assemble it as 64 bit code. You can fix this by passing -m32 in all stages of assembly and linkage. Please keep in mind that WSL does not actually support 32 bit code so you won't be able to run your program even if you manage to assemble it.
gcc tries to generate a position-indepentent executable. To make your code work in such an executable, you need to write position indepentent code. To do so, you need to avoid any absolute references to the addresses of variables. In 32 bit code, this is a bit tricky and I'm not going to explain this further as 32 bit code won't run on WSL anyway. The compiler advises you to compile with -fpic because that causes the compiler to generate position independent code from C files, but for assembly files it's ineffective. You can fix this issue by linking with -no-pie, causing the linker to generate a normal position-dependent binary. Note that this still doesn't mean that a 32 bit binary is going to run in WSL.

Assembling with GCC causes weird relocation error with regards to .data

This is an issue that didn't used to ever occur. I'm pretty convinced it's probably an issue with my package repos (I recently reinstalled my Arch system and this has only just started happening).
I wrote a small hello world in x86_64:
.data
str: .asciz "Test"
.text
.globl main
main:
sub $8, %rsp
mov $str, %rdi
call puts
add $8, %rsp
ret
and then I attempt to assembly and link using GCC - like I have done many times in the past - with, simply:
gcc test.s -o test
and then this error is outputted:
/usr/bin/ld: /tmp/ccAKVV4D.o: relocation R_X86_64_32S against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
This error has never occured for me ever. I've tried to fix the issue by googling the same error message but it comes up with things that are so specific whereas I'd consider this a general issue. I've tried reinstalling base-devel and the entire GCC toolchain. I dunno what else I can do (please don't suggest using nasm, that's heresy).
I'd like to think I'm missing something obvious but I've used GCC for my assembly needs for a long time.
The way to get around this error is to generate a no-pie (Non Position Independent executable) executable :
gcc -no-pie test.s -o test
The reason for this behaviour is as explained by #Ped7g :
Debian switched to PIC/PIE binaries in 64-bits mode & GCC in your case is trying to link your object as PIC, but it will encounter absolute address in mov $str, %rdi.

x86 assembly create Win32 executable NASM

I want to create a valid Win32 executable, that can be run as standalone application.
For example, this simple program:
bits 32
mov eax,1
ret
I compiled it using NASM with
nasm test.asm -o test.exe
Then I ran that program.
It started NTVDM and it told me "The NTVDM CPU encountered illegal instruction" and some technical details, probably dump, and registers.
So, I want to create a standalone Win32 application in assembly language. I don't want to create COM file, like in DOS.
[section] .text
global _start
_start:
mov eax, 1
ret
can be assembled like this:
nasm -fwin32 file.asm (this should give you file.obj)
and
link /subsystem:windows /entry:start file.obj
(or)
ld -e _start file.obj
whatever linker you choose should give you your .exe
At least Windows XP refuses to load an application that does not use any DLL files. I didn't test with Windows 7 up to now!
The reason is that there are no official interfaces but the DLLs that come with Windows and that a program that has neither inputs nor outputs makes no sense.

Cannot find entry symbol _start

My c code on compiling on gcc is giving the error Cannot find entry symbol _start defaulting to 00000. Can anyone tell me why and how to correct it?
The command line is arm-none-eabi-gcc -O3 -march=armv7-a -mtune=cortex-a8 -mfpu=neon -ftree-vectorize -mfloat-abi=softfp file path and the target platform is a-8 sitara cortex processor.
The only reason the compiler threw the above error is because the start code(_start function) generated by the OS for running your code cannot find the default or registered function main. So either you can use _start function instead of main function but the compilation command should be gcc -nostartfiles filename.c but using _start there are a lot of exceptions so better to use main instead.
the -none- part means that your toolchain doesn't build for a particular operating system, so you must define a _start entry point. For non-bare-metal toolchains that build for a particular operating system, _start is provided by the standard library that in order will call main when everything is set up.

Resources