I assembled a simple "Hello, world" program and linked it using TCC, after which I got 4196 bytes of an executable.
The program has 31 sections: ['', '.text', '.data', '.bss', '.symtab', '.strtab', '.rel.text', '.rodata', '.rodata.cst4', '.note.GNU-stack', '.init', '.rel.init', '.gnu.linkonce.t.__x86.get_pc_thunk.bx', '.fini', '.rel.fini', '.text.unlikely', '.text.__x86.get_pc_thunk.bx', '.eh_frame', '.rel.eh_frame', '.preinit_array', '.init_array', '.fini_array', '.interp', '.dynsym', '.dynstr', '.hash', '.dynamic', '.got', '.plt', '.rel.got', '.shstrtab']. I feel that's a real lot for such a simple binary - which ones are actually necessary here for my program to run?
Here's the source code and the way I compiled it:
extern printf
global main
section .data
msg: db "Hello World!", 0
section .text
main:
;; puts (msg)
push msg
call printf
add esp, 4
;; return 0
mov eax, 0
ret
nasm main.asm -f elf32 && tcc main.o -o main
Tested on 32bit/ubuntu:16.04 Docker image.
Note: this question is different from this one in that I'm not looking for a tensy Linux ELF, but one that allows me to call dynamic symbols. I believe that due to the nature of dynamic linking, I need some extra sections.
I believe that due to the nature of dynamic linking, I need some extra sections.
Your belief is mistaken. No section is necessary at runtime, only segments matter.
A runnable dynamically-linked ELF binary will have at least one PT_LOAD segment, a PT_INTERP segment, and PT_DYNAMIC segment.
Related
I'm getting a weird error message when trying to assemble and run a .s file using AT&T Intel Syntax. Not sure if I'm even using the correct architecture to begin with, or if I'm having syntax errors, if I'm not using the correct commands to assemble and link, etc. Completely lost and I do not know where to begin.
So basically, I have a file called yea.s , which contains some simple assembler instructions. I then try to compile it using the command as yea.s -o yea.o and then link is using ld yea.o -o yea. When running ld, I get this weird message:ld: warning: cannot find entry symbol _start; defaulting to 000000440000.
This is the program im trying to run, very simple and doesn't really do anything.
resMsg: .asciz "xxxxxxxx"
.text
.global main
main:
pushq $0
ret
I just cannot figure out what's going on. Obviously, this is for school homework. I'm not looking for the answer to the homework, obviously, but this is the starting point to where I can actually start the coding. And I just cant figure out how to simple run the program, which it doesn't say in the assignment. Anyway, thanks in advance guys!
Linux executables require an entry point to be specified. The entry point is the address of the first instruction to be executed in your program. If not specified otherwise, the link editor looks for a symbol named _start to use as an entry point. Your program does not contain such a symbol, thus the linker complains and picks the beginning of the .text section as the entry point. To fix this problem, rename main to _start.
Note further that unlike on DOS, there is nothing to return to from _start. So your attempt to return is going to cause a crash. Instead, call the system call sys_exit to exit the program:
mov $0, %edi # exit status
mov $60, %eax # system call number
syscall # perform exit call
Alternatively, if you want to use the C runtime environment and call functions from the C library, leave your program as is and instead assemble and link using the C compiler driver cc:
cc -o yea yea.s
If you do so, the C runtime environment provides the entry point for you and eventually tries to call a function main which is where your code comes in. This approach is required if you want to call functions from the C library. If you do it this way, make sure that main follows the SysV ABI (calling convention).
Note that even then your code is incorrect. The return value of a function is given in the eax (resp. rax) register and not pushed on the stack. To return zero from main, write
mov $0, %eax # exit status
ret # return from function
In all currently supported versions of Ubuntu open the terminal and type:
sudo apt install as31 nasm
as31: Intel 8031/8051 assembler
This is a fast, simple, easy to use Intel 8031/8051 assembler.
nasm: General-purpose x86 assembler
Netwide Assembler. NASM will currently output flat-form binary files, a.out, COFF and ELF Unix object files, and Microsoft 16-bit DOS and Win32 object files.
If you are using NASM in Ubuntu 18.04, the commands to compile and run an .asm file named example.asm are:
nasm -f elf64 example.asm # assemble the program
ld -s -o example example.o # link the object file nasm produced into an executable file
./example # example is an executable file
This question already has an answer here:
How to implement system call in ARM64?
(1 answer)
Closed 3 years ago.
Can you let me know what I'm doing wrong?
I'm new to assembly programming and am unfamiliar with the various options in ld.
I've been trying to use the yasm compiler initially but then realised that as is the way to go for the ARM architecture while composing GNU compliant assembly code.
Better luck running as from the binutils package, i.e. the GNU assembler. But the assembly code has to be ARM-compliant.
The following is the code within arm.s:
.text /* Start of the program code section */
.global main /* declares the main identifier */
.type main, %function
main: /* Address of the main function */
/* Program code would go here */
BR LR
/* Return to the caller */
.end /* End of the program */
The above was throwing an Illegal Instruction error. That can be fixed
by substituting ret for BR LR. This is new to ARM V8.
ARM, a RISC architecture, is not supported by YASM.
My build file is as follows:
#/usr/bin/env bash
#display usage
[ $# -eq 0 ] && { echo "Usage: $0 <File Name without extension> ";exit 1; }
set +e
rm -f $1.exe $1 $1.o
as -o $1.o $1.s
[ -e $1.o ] && { file $1.o;}
gcc -s -o $1.exe $1.o -fpic
ld -s -o $1 -pie --dynamic-linker /system/bin/linker64 /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o $1.o -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/crtend_android.o
[ -e $1.exe ] && { file $1.exe;nohup ./$1.exe; }
[ -e $1 ] && { file $1;nohup ./$1;}
set -e
The code was causing either a segmentation fault or a bus error earlier.
I was able to run a program or two without any segmentation or bus errors with the updated build file above. I set up the build file to produce two executables, one using gcc and the other ld, since some online tutorials use ld instead of gcc for the linking step. Using the verbose setting of gcc, you can look at the options passed to the linker and thus mimic the same for the linker independently.
There may be some redundant settings that I've missed.
You can access updates to the source code and build file at
Learn Assembly.
Check out this resource from Keil here. arm Keil product guides
More resources:
https://thinkingeek.com/2016/10/08/exploring-aarch64-assembler-chapter1/
How to link a gas assembly program that uses the C standard library with ld without using gcc?
While the above problem appears to be fixed for now, I have errors running the following code:
.text
.global main
main:
mov w0, #2
mov w7, #1 // request to exit program
svc 0
I obtain an illegal instruction error when I try to execute the code.
Secondly, if I alter the main to _start (since I don't want to be using main all the time), I have the following error from the buildrun script.
./buildrun myprogram
/data/data/com.termux/files/usr/bin/aarch64-linux-android-ld: myprogram.o: in function `_start': (.text+0x0): multiple definition of `_start'; /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o:crtbegin.c:(.text+0x0): first defined here /data/data/com.termux/files/usr/bin/aarch64-linux-android-ld: /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o: in function `_start_main': crtbegin.c:(.text+0x38): undefined reference to `main
/data/data/com.termux/files/usr/bin/aarch64-linux-android-ld: crtbegin.c:(.text+0x3c): undefined reference to `main' clang-8: error: linker command failed with exit co
de 1 (use -v to see invocation)
ld: myprogram.o: in function `_start': (.text+0x0): multiple definition of `_start'; /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o:crtbegin.c:(.text+0x0): first defined here ld: /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o: in function `_start_main': crtbegin.c:(.text+0x38): undefined reference to `main'
ld: crtbegin.c:(.text+0x3c): undefined reference to `main'
How do I create programs with entry points other than main?
I want to be able to :
Create a statically linked executable that works.
Create an executable that has a function named _start instead of main.
This file builds static executables that don't use main or call any library calls.
Create a dynamically linked executable with an entry point other than main.
My build file handles this, sort of, with the entry point as second parameter.
Create an executable that uses supervisor call svc to exit without throwing an illegal instruction error as against using ret.
I was able to call svc by setting the system call number in register X8 as against W7 in version 7 ARM. Additionally, ARM 64 has renumbered the system call numbers as per the following header file.
https://github.com/torvalds/linux/blob/v4.17/include/uapi/asm-generic/unistd.h
https://reverseengineering.stackexchange.com/q/16917
.data
.balign 8
labs: .asciz "Azeria Labs\n" //.asciz adds a null-byte to the end of the string .balign 8 after_labs: .set size_of_labs, after_labs - labs .balign 8 addr_of_labs: .dword labs .balign 8 .text
.global main
main:
mov x0, #1 //STDOUT ldr x1,addr_of_labs //memory address of labs mov w2, #size_of_labs //size of labs mov x8,#64 svc #0x0 // invoke syscall _exit: mov x8, #93 //exit syscall
svc #0x0 //invoke syscall
The above code was ported from the example code listed below.
https://azeria-labs.com/writing-arm-shellcode/
Compacting the data section into one instead of splitting it as in the example from the site mitigates the relocation errors while linking.
Other useful references:
https://thinkingeek.com/2013/01/09/arm-assembler-raspberry-pi-chapter-1/
*Check the comment by ehrt74 on the above post for the motivation to explore svc call further. *
Yasm is an x86 assembler. It cannot produce executables for an ARM processor.
The tutorials you are working with are describing x86 assembly. They are intended to be followed on an x86 system.
Working under Linux, i just met the following issue. (For sure, someone will give me the answer, but up to now,i didn't find any simple and clear answer :)
/*compile with gcc -o out.x hello.c*/
#include<stdio.h>
int main()
{
printf("Hello World2\r\n");
printf("Hello World3\r\n ");
return 0;
}
Running the following code under Linux give two strings BUT the ending char are differents: the first output ends with 0x0d while the 2nd ends with 0x0d,0x0a.
This is something done by the compiler (GCC) as you can see in the obj file:
Contents of section .rodata:
400610 01000200 48656c6c 6f20576f 726c6432 ....Hello World2
400620 0d004865 6c6c6f20 576f726c 64330d0a ..Hello World3..
400630 2000 .
So, questions are:
Why ?
How can i avoid this kind of "optimization"(!?)
Thanks
Creating formatted output at runtime takes time; the printf call is slow. GCC knows this, so replaces the first function with a call to puts. Since puts automatically adds a \n, GCC needs to remove the \n from the string to compensate.
GCC does this because it considers printf a built-in. Because this has no effect on the bytes output or even on the number of calls to write; I strongly recommend leaving it as-is. If you do want to disable it, you can pass -fno-builtin-printf, but the only effect will be to slow down your code as it tries to format the string unnecessarily.
It is simpler to ask GCC (using GCC7.2 on Linux/Debian/Sid/x86-64) to emit assembler. So I compiled your program bflash.c with
gcc -fverbose-asm -O0 -S bflash.c -o bflash-O0.S
to get it without optimization, and with
gcc -fverbose-asm -O1 -S bflash.c -o bflash-O1.S
to get -O1 optimization. Feel free to repeat the experiment with various other optimization flags.
Even without optimization, the bflash-O0.S contains:
.section .rodata
.LC0:
.string "Hello World2\r"
.LC1:
.string "Hello World3\r\n "
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp #,
.cfi_def_cfa_register 6
# bflash.c:5: printf("Hello World2\r\n");
leaq .LC0(%rip), %rdi #,
call puts#PLT #
# bflash.c:6: printf("Hello World3\r\n ");
leaq .LC1(%rip), %rdi #,
movl $0, %eax #,
call printf#PLT #
# bflash.c:8: return 0;
movl $0, %eax #, _4
# bflash.c:9: }
popq %rbp #
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
As you see, the first printf has been optimized as a puts; and this is permitted by the C11 standard n1570 (as-if rule). BTW, the bflash-01.S contains similar code. Notice that the C11 standard has been specified with current optimization practices in mind (many members of the standardization committees are compiler implementors).
BTW Clang 5, invoked as clang-5.0 -O1 -fverbose-asm -S bflash.c -o bflash-01clang.s, performs the same kind of optimization.
How can i avoid this kind of "optimization"(!?)
Follow Daniel H's answer (and you might compile with -ffreestanding, but I don't recommend that).
Or avoid using printf from the <stdio.h> and implement your own slower printing function. If you implement your own printing function, name it differently (since printf is defined in the C11 standard), and perhaps (if so wanted) write your own GCC plugin to optimize it your way (and that plugin should better be some free software which is GPL compatible, read the GCC runtime library exception).
The C language specification (study n1570) defines a semantics, that is the behavior of your compiled program. It does not require any particular sequence of bytes to appear in the executable (which is probably not even mentioned in the standard). If you need such a property, find a different programming language, and give up all the important optimizations GCC is trying hard to do for you. Optimizations are what is making writing a C compiler difficult (if you want a non-optimizing compiler, use something else than GCC, but accept to lose perhaps a factor of three or more in performance, w.r.t. code compiled with gcc -O2).
I'm interested in building a static ELF program without (g)libc, using unistd.h provided by the Linux headers.
I've read through these articles/question which give a rough idea of what I'm trying to do, but not quite:
http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
Compiling without libc
https://blogs.oracle.com/ksplice/entry/hello_from_a_libc_free
I have basic code which depends only on unistd.h, of which, my understanding is that each of those functions are provided by the kernel, and that libc should not be needed. Here's the path I've taken that seems the most promising:
$ gcc -I /usr/include/asm/ -nostdlib grabbytes.c -o grabbytesstatic
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400144
/tmp/ccn1mSkn.o: In function `main':
grabbytes.c:(.text+0x38): undefined reference to `open'
grabbytes.c:(.text+0x64): undefined reference to `lseek'
grabbytes.c:(.text+0x8f): undefined reference to `lseek'
grabbytes.c:(.text+0xaa): undefined reference to `read'
grabbytes.c:(.text+0xc5): undefined reference to `write'
grabbytes.c:(.text+0xe0): undefined reference to `read'
collect2: error: ld returned 1 exit status
Before this, I had to manually define SEEK_END and SEEK_SET according to the values found in the kernel headers. Else it would error saying that those were not defined, which makes sense.
I imagine that I need to link into an unstripped vmlinux to provide the symbols to utilize. However, I read through the symbols and while there were plenty of llseeks, they were not llseek verbatim.
So my question can go in a few directions:
How can I specify an ELF file to utilize symbols from? And I'm guessing if/how that's possible, the symbols won't match up. If this is correct, is there an existing header file which will redefine llseek and default_llseek or whatever is exactly in the kernel?
Is there a better way to write Posix code in C without a libc?
My goal is to write or port fairly standard C code using (perhaps solely) unistd.h and invoke it without libc. I'm probably okay without a few unistd functions, and am not sure which ones exist "purely" as kernel calls or not. I love assembly, but that's not my goal here. Hoping to stay as strictly C as possible (I'm fine with a few external assembly files if I have to), to allow for a libc-less static system at some point.
Thank you for reading!
If you're looking to write POSIX code in C, the abandonment of libc is not going to be helpful. Although you could implement a syscall function in assembler, and copy structures and defines from the kernel header, you would essentially be writing your own libc, which almost certainly would not be POSIX compliant. With all the great libc implementations out there, there's almost no reason to begin implementing your own.
dietlibc and musl libc are both frugal libc implementations which yield impressively small binaries The linker is generally smart; as long as a library is written to avoid the accidentally pulling in numerous dependencies, only the functions you use will actually be linked into your program.
Here is a simple hello world program:
#include<unistd.h>
int main(){
char str[] = "Hello, World!\n";
write(1, str, sizeof str - 1);
return 0;
}
Compiling it with musl below yeilds a binary of a less than 3K
$ musl-gcc -Os -static hello.c
$ strip a.out
$ wc -c a.out
2800 a.out
dietlibc produces an even smaller binary, less than 1.5K:
$ diet -Os gcc hello.c
$ strip a.out
$ wc -c a.out
1360 a.out
This is far from ideal, but a little bit of (x86_64) assembler has me down to just under 5KB (but most of that is "other things than code" - the actual code is under 1KB [771 bytes to be precise], but the file size is much larger, I think because the code size is rounded to 4KB, and then some header/footer/extra stuff is added to that]
Here's what I did:
gcc -g -static -nostdlib -o glibc start.s glibc.c -Os -lc
glibc.c contains:
#include <unistd.h>
int main()
{
const char str[] = "Hello, World!\n";
write(1, str, sizeof(str));
_exit(0);
}
start.s contains:
.globl _start
_start:
xor %ebp, %ebp
mov %rdx, %r9
mov %rsp, %rdx
and $~16, %rsp
push $0
push %rsp
call main
hlt
.globl _exit
_exit:
// We known %RDI already has the exit code...
mov $0x3c, %eax
syscall
hlt
That main point of this is not to show that it's not the system call part of glibc that takes up a lot of space, but the "prepar things" - and beware that if you were to call for example printf, possibly even (v)sprintf, or exit(), or any other "standard library" function, you are in the land of "nobody knows what will happen".
Edit: Updated "start.s" to put argc/argv in the right places:
_start:
xor %ebp, %ebp
mov %rdx, %r9
pop %rdi
mov %rsp, %rsi
and $~16, %rsp
push %rax
push %rsp
// %rdi = argc, %rsi=argv
call main
Note that I've changed which register contains what thing, so that it matches main - I had them slightly wrong order in the previous code.
What's the best tool for converting PE binaries to ELF binaries?
Following is a brief motivation for this question:
Suppose I have a simple C program.
I compiled it using gcc for linux(this gives ELF), and using 'i586-mingw32msvc-gcc' for Windows(this gives a PE binary).
I want to analyze these two binaries for similarities, using Bitblaze's static analysis tool - vine(http://bitblaze.cs.berkeley.edu/vine.html)
Now vine doesn't have a good support for PE binaries, so I wanted to convert PE->ELF, and then carry on with my comparison/analysis.
Since all the analysis has to run on Linux, I would prefer a utility/tool that runs on Linux.
Thanks
It is possible to rebuild an EXE as an ELF binary, but the resulting binary will segfault very soon after loading, due to the missing operating system.
Here's one method of doing it.
Summary
Dump the section headers of the EXE file.
Extract the raw section data from the EXE.
Encapsulate the raw section data in GNU linker script snippets.
Write a linker script to build an ELF binary, including those scripts from the previous step.
Run ld with the linker script to produce the ELF file.
Run the new program, and watch it segfault as it's not running on Windows (and it tries to call functions in the Import Address Table, which doesn't exist).
Detailed Example
Dump the section headers of the EXE file. I'm using objdump from the mingw cross compiler package to do this.
$ i686-pc-mingw32-objdump -h trek.exe
trek.exe: file format pei-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 AUTO 00172600 00401000 00401000 00000400 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .idata 00001400 00574000 00574000 00172a00 2**2
CONTENTS, ALLOC, LOAD, DATA
2 DGROUP 0002b600 00576000 00576000 00173e00 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .bss 000e7800 005a2000 005a2000 00000000 2**2
ALLOC
4 .reloc 00013000 0068a000 0068a000 0019f400 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .rsrc 00000a00 0069d000 0069d000 001b2400 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
Use dd (or a hex editor) to extract the raw section data from the EXE. Here, I'm just going to copy the code and data sections (named AUTO and DGROUP in this example). You may want to copy additional sections though.
$ dd bs=512 skip=2 count=2963 if=trek.exe of=code.bin
$ dd bs=512 skip=2975 count=347 if=trek.exe of=data.bin
Note, I've converted the file offsets and section sizes from hex to decimal to use as skip and count, but I'm using a block size of 512 bytes in dd to speed up the process (example: 0x0400 = 1024 bytes = 2 blocks # 512 bytes).
Encapsulate the raw section data in GNU ld linker scripts snippets (using the BYTE directive). This will be used to populate the sections.
cat code.bin | hexdump -v -e '"BYTE(0x" 1/1 "%02X" ")\n"' >code.ld
cat data.bin | hexdump -v -e '"BYTE(0x" 1/1 "%02X" ")\n"' >data.ld
Write a linker script to build an ELF binary, including those scripts from the previous step. Note I've also set aside space for the uninitialized data (.bss) section.
start = 0x516DE8;
ENTRY(start)
OUTPUT_FORMAT("elf32-i386")
SECTIONS {
.text 0x401000 :
{
INCLUDE "code.ld";
}
.data 0x576000 :
{
INCLUDE "data.ld";
}
.bss 0x5A2000 :
{
. = . + 0x0E7800;
}
}
Run the linker script with GNU ld to produce the ELF file. Note I have to use an emulation mode elf_i386 since I'm using 64-bit Linux, otherwise a 64-bit ELF would be produced.
$ ld -o elf_trek -m elf_i386 elf_trek.ld
ld: warning: elf_trek.ld contains output sections; did you forget -T?
$ file elf_trek
elf_trek: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, not stripped
Run the new program, and watch it segfault as it's not running on Windows.
$ gdb elf_trek
(gdb) run
Starting program: /home/quasar/src/games/botf/elf_trek
Program received signal SIGSEGV, Segmentation fault.
0x0051d8e6 in ?? ()
(gdb) bt
\#0 0x0051d8e6 in ?? ()
\#1 0x00000000 in ?? ()
(gdb) x/i $eip
=> 0x51d8e6: sub (%edx),%eax
(gdb) quit
IDA Pro output for that location:
0051D8DB ; size_t stackavail(void)
0051D8DB proc stackavail near
0051D8DB push edx
0051D8DC call [ds:off_5A0588]
0051D8E2 mov edx, eax
0051D8E4 mov eax, esp
0051D8E6 sub eax, [edx]
0051D8E8 pop edx
0051D8E9 retn
0051D8E9 endp stackavail
For porting binaries to Linux, this is kind of pointless, given the Wine project.
For situations like the OP's, it may be appropriate.
I've found a simpler way to do this. Use the strip command.
Example
strip -O elf32-i386 -o myprogram.elf myprogram.exe
The -O elf32-i386 has it write out the file in that format.
To see supported formats run
strip --info
I am using the strip command from mxe, which on my system is actually named /opt/mxe/usr/bin/i686-w64-mingw32.static-strip.
I don't know whether this totally fits your needs, but is it an option for you to cross-compile with your MinGW version of gcc?
I mean do say: does it suit your needs to have i586-mingw32msvc-gcc compile direct to ELF format binaries (instead of the PEs you're currently getting). A description of how to do things in the other direction can be found here - I imagine it will be a little hacky but entirely possible to make this work for you in the other direction (I must admit I haven't tried it).