what are the correct flags to mix assembly and C without losing .data constants - gcc

I am working on a utility in assembler (x86, NASM 2.13, gcc 7.50, Ubuntu 18.X) to be called from C. The problem that I am running into is that the string constant addresses seem to be lost in the making process, so messages are not printing. I can see the string constants in the final binary.
This is the sample assembler code
SECTION .data
error_len_message: db "test", 10
error_len_message_len: equ $-error_len_message
SECTION .text
global test_func
test_func:
mov eax, 4
mov ebx, 1
mov ecx, error_len_message
mov edx, error_len_message_len
int 80H
The header file would be trivial as it would only need the signature used in main.c
#include "....."
int main(void) {
test_func();
return 0;
}
The make file of the executable is as follows:
util_tests: ../asm/utilities/utilities.o
gcc -Wall -o ./build/$# main.c $?
../asm/utilities/utilities.o:
cd ../asm/utilities && make && cd ../../util_tests;
clean:
cd ../asm/utilities && make clean && cd ../../util_tests;
The make file of the utilities is as follows:
utilities.o: test/test.o
ld $? -o $#
test/test.o:
cd test && make && cd ..;
clean:
cd test && make clean && cd ..;
rm *.o
The make file of test assembler code is:
test.o: test.asm
nasm -f elf64 -g -F dwarf $?
clean:
rm *.o
I have no trouble turning this into an executable using assembler only and printing strings defined in .data section. Make file:
test: test.o
ld -o test $^
test.o: *.asm
nasm -f elf64 -g -F stabs $?
clean:
rm *.o
I can successfully define and use variables in the .bss section (not shown for brevity)
The problem, I believe, is in the way I am building the utility. Thanks in advance!

So after adding the pertinent "default rel" to the assembler source file, removing direct calls to int 80H, and adding calls printf, the linker fails because it also tries to relocate "printf#glibc_x.x.x". After trying linker options to ignore unresolved symbols, it seems like a dead end.
So it seems there are only two choices, assemble in 32 bit to avoid problems with "int 80H", or return status/results and let the caller deal with the rest. The following assemble, link, and gdb displays labels and offsets matching correctly
DEFAULT REL
SECTION .text
global silly
silly:
lea r9, [message]
ret
SECTION .data
message: db "A Message", 10
Makefile:
silly.so: silly.o
ld -shared $? -o $#
silly.o: silly.asm
nasm -f elf64 -g -F dwarf $?
clean:
rm *.o
rm *.so
Hopefully, this would be useful to anyone

Related

How do I compile assembly?

The problem is that I have a filesystem in documents/assembly that goes like this:
test.s:
.global _start
.text
_start:
mov $60, %rax # exit
mov $0, %rdi # return code 0
syscall
test.o:
\* exists \*
compile.bash:
as -o test.o test.s && ld -e _start -o test.s test.o && chmod 777 test.o && (./test ; echo $?)
But when I try running compile.bash I get:
ld: dynamic executables or dylibs must link with libSystem.dylib for architecture x86_64
And when I try running test.o:
bash: ./test.o: cannot execute binary file
I'm using gnu assembler, But instead of gcc in the tutorial I say as.
I tried changing the command, But what happened was that it gave a lot of errors. I'm using macos monetary version 12.5.1 (21G83). What I expected was it to print 0 when running the command, But it didn't.

Using make, how do I protect against this behavior with .c files in an assembly project?

I'm making a super easy NASM x86_64 assembly program mytest.asm
BITS 64
GLOBAL _start
SECTION .text
_start:
mov rax, 60 ; 'exit' system call
mov rdi, 42 ; exit with error code 42
syscall
All this program does is exit with status 42. I made a very simple Makefile for it,
AS=nasm
ASFLAGS=-f elf64
.PHONY: all
all: mytest
%.o : %.asm
$(AS) $(ASFLAGS) -o "$#" "$<"
% : %.o
$(LD) $(LDFLAGS) -o "$#" "$<"
When executed, this works fine,
nasm -f elf64 -o "mytest.o" "mytest.asm"
ld -m elf_x86_64 -o "mytest" "mytest.o"
rm mytest.o
Unless there is a file by the same name with .c, for example here mytest.c
// exits with status 66
int main () {
__asm__ (
"mov $60, %%rax\n\t"
"mov $66, %%rdi\n\t"
"syscall\n\t"
::: "%rax", "%rdi"
);
}
If I run make with the following file the C code actually gets compiled to mytest.
And awkwardly, $(LDARGS) gets sent to $(CC) and not to $(LD). This seems insecure to me, anyone with this very typical Makefile can generate executable from code name by inserting a .c file with the same name?
Is this behavior documented by GNU Make?
GNU Make 4.1
Built for x86_64-pc-linux-gnu
Ideally, the presence of the .c files wouldn't affect the assembly build stream.
This comes from Make’s built-in rules. Make knows how to build executables from C files, so when you ask it to build mytest (which is what make does since you have an all target requiring mytest), it builds up its dependency tree and notes that:
it can build mytest from mytest.c, following its built-in rule;
it can build mytest from mytest.o, following the rule you’ve specified;
it can build mytest.o from mytest.c, following its built-in rule;
it can build mytest.o from mytest.asm, following the rule you’ve specified.
The first rule wins (I’m not sure what the precedence is), and that’s what it does.
You can disable this using the -r option:
make -r mytest
will always use your rules to build the program.
You can also cancel built-in rules either
individually by redefining them:
% : %.c
at the end of your Makefile will disable that built-in rule and result in the behaviour you’re after;
globally by specifying MAKEFLAGS += -r in your Makefile.

MinGW Win32 + nasm: "undefined reference"

I am currently developing an OS for learning purposes, and it's been working fine until now. Then I tried to call an assembler function, compiled with nasm, -fwin32, from C code, but all I got was an "undefined reference" error. I have created a small example in pure assembler, which has the same problem, but is easily understandable and way smaller:
It includes two files:
test.asm:
[bits 32]
global _testfunc
_testfunc:
ret
test2.asm:
[bits 32]
extern _testfunc
global _testfunc2
_testfunc2:
call _testfunc
ret
Here is my compiler / linker script (using windows batch files):
nasm.exe -f win32 test.asm -o test.o
nasm.exe -f win32 test2.asm -o test2.o
ld test.o test2.o -o output.tmp
This results in the error:
test2.o:test2.asm:(.text+0x1): undefined reference to `testfunc'
To extend the question, the same happens when the function is called from C:
test.c:
extern void testfunc(void);
void start()
{
testfunc();
}
With this linker script:
gcc -ffreestanding -c test.c -o testc.o
nasm.exe -f win32 test.asm -o test.o
ld test.o testc.o -o output.tmp
In test.o, test2.o and testc.o, it always says _testfunc, so the error has nothing to do with leading underscores!
In my MinGW setup you need a section directive before the code.
; foo.asm
[bits 32]
global _testfunc
section .text
_testfunc:
ret
Then assemble to win32 format:
nasm -fwin32 foo.asm -o foo.o
Now you can check that testfunc is there:
$ nm foo.o
00000000 a .absolut
00000000 t .text
00000001 a #feat.00
00000000 T _testfunc
The T means text section global, so we're good to go.
Note I'd avoid naming anything test since this is a shell command. This can cause endless grief.
The C function is as you showed it, but name the file something else:
// main.c
extern void testfunc(void);
int main(void)
{
testfunc();
return 0;
}
Then to build an executable let gcc do the heavy lifting because ld sometimes needs arcane arguments.
gcc -ffreestanding main.c foo.o -o main
Your missing something important, your code is not in a code section!
Your asm files should look like the following:
test.asm
global _testfunc
section .text ; <<<< This is important!!!
; all code goes below this!
_testfunc:
ret
test2.asm
extern _testfunc
global _testfunc2
section .text ; <<<< Again, this is important!!!
_testfunc2:
call _testfunc
ret

Nasm on Mac OS X - how to compile and read the debug

I'm trying to learn assembly and I'm using Nasm v2.10.07 on Mac OS X (Snow Leopard).
I can compile, but I need to read the Debug file, that is a .o file.
This is what I compile:
global _main
section.data
M db 5,4,3,2,1
dim equ $-M
section.text
_main:
mov edi, M
mov eax, 0
mov ebx, 1
int 80h
This is how I compile:
nasm -f elf -g -F stabs myfile.asm -o myfile.o
And this is the result:
ELF����������������������#�������4�����(�
�������������������������������������������������������������������–������������������������������������?��������������������������������0��M��������������������������������Ä��ê���������������"����������������2������������������*��� �����������P�����������������4��������������`��T����������������:��������������¿��������������������C��� �����������–��0���������������ø����∏����ª���ÕÄ�%define $�The Netwide Assembler 0.98.40 (Apple Computer, Inc. build 11)���.text�.comment�.shstrtab�.symtab�.strtab�.rel.text�.stab�.stabstr�.rel.stab��%d����������������������������Òˇ�������������Òˇ������������������������������������������������������Òˇ�������������,�������������myfile.asm�section.data�M�dim�section.text�_main��%define $_%1 ������%define������������d�����������D����������D���������D��
�������D� ��������D�
�����%define $_%�myfile.asm��%de����� �����,�����8�����D�����P�����
So, what should I do to read in the correct way the debug without those strange symbols?
To show the contents of the .stabs section, use objdump -g myfile.o or objdump -G myfile.o
To get the full source code with line numbers taken from the debug section, use objdump -S -l myfile.o

NASM Hello World either segfaults or bus errors in Mac OS X

I'm writing Hello World in NASM, and I can get it to echo Hello World to the console, but the program segfaults if I don't run it with Make.
Trace with Makefile:
$ make
nasm -f macho -o hello.o --prefix _ hello.asm
ld -o hello hello.o -arch i386 -lc -macosx_version_min 10.6 -e _start -no_pie
./hello
Hello World!
Trace with manual commands:
$ nasm -f macho -o hello.o --prefix _ hello.asm
$ ld -o hello hello.o -arch i386 -lc -macosx_version_min 10.6 -e _start -no_pie
$ ./hello
Segmentation fault: 11
hello.asm:
[bits 32]
section .data
msg: db "Hello World!", 0
section .text
global start
extern puts
extern exit
start:
push msg
call puts
add esp, 4
push 0
call exit
Makefile:
# Linux defaults
FORMAT=-f elf
MINV=
ARCH=-arch i386
LIBS=
RUN=./
EXECUTABLE=hello
PREFIX=
ENTRY=
PIE=
# Windows
ifeq (${MSYSTEM},MINGW32)
FORMAT=-f win32
EXECUTABLE=hello.exe
PREFIX=--prefix _
ENTRY=-e _start
ARCH=
LIBS=c:/strawberry/c/i686-w64-mingw32/lib/crt2.o -Lc:/strawberry/c/i686-w64-mingw32/lib -lmingw32 -lmingwex -lmsvcrt -lkernel32
ENTRY=
RUN=
endif
# Mac OS X
ifeq ($(shell uname -s),Darwin)
FORMAT=-f macho
PREFIX=--prefix _
ENTRY=-e _start
LIBS=-lc
MINV=-macosx_version_min 10.6
PIE=-no_pie
endif
all: test
test: $(EXECUTABLE)
$(RUN)$(EXECUTABLE)
$(EXECUTABLE): hello.o
ld -o $(EXECUTABLE) hello.o $(ARCH) $(LIBS) $(MINV) $(ENTRY) $(PIE)
hello.o: hello.asm
nasm $(FORMAT) -o hello.o $(PREFIX) hello.asm
clean:
-rm $(EXECUTABLE)
-rm hello.o
Specs:
ld 64-134.9
LLVM 3.1svn
NASM 0.98.40
Make 3.81
Xcode 4.5
Mac OS X 10.8.1
MacBook Pro 2009
2 things, your hello world string is not NULL terminated and as I mentioned in another post, when you use C functions, you MUST adjust esp after each call
You tore down your stack frame twice:
mov esp, ebp
pop ebp
...
leave
You only need one of those, since leave is equivalent to mov esp, ebp; pop ebp.
See http://michaux.ca/articles/assembly-hello-world-for-os-x for several example hello world programs. Note that all of them exit the program explicitly with
; 2a prepare the argument for the sys call to exit
push dword 0 ; exit status returned to the operating system
; 2b make the call to sys call to exit
mov eax, 0x1 ; system call number for exit
sub esp, 4 ; OS X (and BSD) system calls needs "extra space" on stack
int 0x80 ; make the system call
because you cannot ret from an entry point (there's nothing to return to).
Also note that if you call the function main and don't supply the e option to ld, then libc's entry point will be called. In that case, it is permissible to ret since you will return control to libc (which calls exit on your behalf).

Resources