Why do my results different following along the tiny asm example?
-static
is not the default even with -nostdlib
when GCC is configured to make PIEs by default. Use gcc -m32 -static -nostdlib
to get the historical behaviour. (-static
implies -no-pie
). See What's the difference between "statically linked" and "not a dynamic executable" from Linux ldd? for more.
Also, you may need to disable alignment of other sections with gcc -Wl,--nmagic
or using a custom linker script, and maybe disable extra sections of metadata that GCC adds. Minimal executable size now 10x larger after linking than 2 years ago, for tiny programs?
You probably don't have a .eh_frame
section if you're not linking any compiler-generated (from C) .o
files. But if you were, you can disable that with gcc -fno-asynchronous-unwind-tables
. (See also How to remove "noise" from GCC/clang assembly output? for general tips aimed at looking at the compiler's asm text output, moreso than executable size.)
See also GCC + LD + NDISASM = huge amount of assembler instructions (ndisasm doesn't handle metadata at all, only flat binary, so it "disassembles" metadata. So the answer there includes info on how to avoid other sections.)
GCC -Wl,--build-id=none
will avoid including a .note.gnu.build-id
section in the executable.
$ nasm -felf32 foo.asm
$ gcc -m32 -static -nostdlib -Wl,--build-id=none -Wl,--nmagic foo.o
$ ll a.out
-rwxr-xr-x 1 peter peter 488 Dec 26 18:47 a.out
$ strip a.out
$ ll a.out
-rwxr-xr-x 1 peter peter 248 Dec 26 18:47 a.out
(Tested on x86-64 Arch GNU/Linux, NASM 2.15.05, gcc 10.2, ld
from GNU Binutils 2.35.1.)
You can check on the sections in your executable with readelf -a a.out
(or use a more specific option to only get part of readelf
's large output.) e.g. before stripping,
$ readelf -S unstripped_a.out
...
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08048060 000060 00000c 00 AX 0 0 16
[ 2] .symtab SYMTAB 00000000 00006c 000070 10 3 3 4
[ 3] .strtab STRTAB 00000000 0000dc 000021 00 0 0 1
[ 4] .shstrtab STRTAB 00000000 0000fd 000021 00 0 0 1
And BTW, you definitely do not want to use nasm -felf64
on a file that uses BITS 32
, unless you're writing a kernel or something that switches from 64-bit long mode to 32-bit compat mode. Putting 32-bit machine code in a 64-bit object file is not helpful. Only ever use BITS
when you want raw binary mode to work (later in that tiny-ELF tutorial). When you're making a .o
to link, it only makes it possible to shoot yourself in the foot; don't do it. (Although it's not harmful if you do properly use nasm -felf32
that matches your BITS directive.)
GCC + LD + NDISASM = huge amount of assembler instructions
As I concluded from @Michael Petch comments:
The binary representation of required function is represented by 00000000-0000001B lines of code snippet of the disassembled file and executes command ret at the end so the second part of the file (0000001B-00000056) is never executed - it's metadata.
As per @Michael Petch and @Jester comments:
I could figure out that the object file consists of many sections https://en.wikipedia.org/wiki/Object_file
The generated basic.o file originally had three sections:
- .text (function itself)
- .comment (not represented in the binary file)
- .eh_frame
What is .eh_frame section and why GCC compiler creates it, is described here:
Why GCC compiled C program needs .eh_frame section?
By running gcc with argument -fno-asynchronous-unwind-tables I could get rid of .eh_frame section from object file.
Following is some assembly code by VS2012, how can I write it on gcc?
You can write it in gcc as:
#include <stdio.h>
int main ()
{
int a = 0 ;
/*How can I write it on gcc*/
__asm__ __volatile__ (
"movl $2, %0\n\t"
"addl $4, %0\n\t"
:"=r"(a) /* =r(egister), =m(emory) both fine here */
);
printf ("%d\n",a );
return 0 ;
}
MASM SEG operator
In MASM the label MY_VAR
translates to the offset part of the address of MY_VAR relative to the segment it was declared in (if you use it like mov ax, MY_VAR
) or relative the to segment you have assumed for the segment register you are using to access it (if you use it like mov ax, WORD PTR [MY_VAR]
).
As you know a given variable (in general a linear address) has multiple logical address, for example the variable at 8000h
linear can be accessed as 0800h:0000h
or 0700h:1000h
and so so.
The form MY_SEG:MY_VAR
tell the assembler to compute the offset relative to the segment MY_SEG
. So if MY_SEG starts at 7000h
linear, MY_SEG2
starts at 6000h
linear then for a var MY_VAR at 8000h
linear MY_SEG:MY_VAR
is 1000h and MY_SEG2:MY_VAR
is 2000h.
The SEG
directive compute the segment part of the logical address instead of the offset, it is the segment MASM used (again by the rules given above) to compute the offset.
In your first instructions you are telling MASM to put the address (let's leaving relocation behind) of the segment MY_SEG
in AX (so if the segment starts at 5000h the value in AX is 500h).
In your second instructions your are explicit telling MASM to use the segment MY_SEG in computing the offset of MY_VAR
and then, by the SEG
directive, telling it to return the segment part instead, that is MY_SEG
.
So they are the same but the second one is redundant.
Related Topics
Linux Script to Automate Ftp Operation
How to Get Details of All Modules/Drivers That Were Initialized/Probed During the Linux Kernel Boot
Matlab Mex Socket Wrapper Library
Copy Differences Between Two Files in Unix
How to List One Filename Per Output Line in Linux
How to Find Files Recursively by File Type and Copy Them to a Directory
What's the Difference of Redirect an Output Using ">", "&>", ">&" and "2&>"
Limiting the Time a Program Runs in Linux
What Actually Is $Rpm_Build_Root
Aslr Bits of Entropy of Mmap()
How to Detect Usb Drive Insertion in Linux
Dyld_Library_Path Environment Variable Is Not Forwarded to External Command in Makefile on MACos
Backing Up (And Restoring) a Plone Instance
How to Request a File But Not Save It with Wget