Gcc -g What happens? - debugging

The assembly file is obtained by using gcc -g -S, and the part of .s file is as follows:
.L3:
.loc 1 22 11
mov eax, DWORD PTR -12[rbp]
mov edx, eax
mov rcx, QWORD PTR .refptr._ZSt4cout[rip]
call _ZNSolsEi
.loc 1 22 18
mov rdx, QWORD PTR .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_[rip]
mov rcx, rax
call _ZNSolsEPFRSoS_E
.loc 1 23 7
mov DWORD PTR -12[rbp], 0
.loc 1 12 2
add DWORD PTR -4[rbp], 1
jmp .L6
What does .loc 1 22 11 stand for?

When the -g flag is added to gcc it directs the compiler to add debugging information. .loc appears only when the compiler generates debugging information with -g flag:
https://sourceware.org/binutils/docs-2.38/as/Loc.html#Loc

Related

ReadConsoleA crashes when inside function in assembly

Recently I have been trying to learn assembly x86 using NASM on a Windows platform, I am trying to make a function that reads a character from stdin ignoring any line feeds and carriage returns, but the problem is that when the function reaches the ret operation the program crashes, strangely when i run the function without the call to ReadConsoleA
the program finishes correctly.
Code:
section .bss
temp_char resb 1
bytes_written_holder resq 1
section .data
global _start
extern GetStdHandle, WriteConsoleA, ReadConsoleA, ExitProcess
section .text
getinput:
mov rcx, -10
call GetStdHandle
mov rcx, rax
mov rdx, temp_char
mov r8, 1
mov r9, bytes_written_holder
push 0
call ReadConsoleA
mov al, [temp_char]
cmp al, 0xa
je getinput
cmp al, 0xd
je getinput
ret
_start:
call getinput
mov rcx, -11
call GetStdHandle
mov rcx, rax
mov rdx, temp_char
mov r8, 1
mov r9, bytes_written_holder
push 0
call WriteConsoleA
mov rcx, 0
call ExitProcess
I am using NASM to assemble and GoLink to link:
nasm -f win64 printtest.s -o printtest.obj
GoLink.exe /console /entry _start printtest.obj kernel32.dll

Access violation while requesting memory in getmem.inc

I'm trying to understand an access violation (c0000005) in my C++ program build with "Codegear C++ Builder 2009"
I have catched the access violation with procdump and analysed it with WinDbg.
Here is the information i gathered with WinDbg.:
Callstack:
# ChildEBP RetAddr Args to Child
>00 0d98f960 004b3728 0001e000 108c6af0 0001e000 MMIServer!SystemSysGetMem$qqri+0x316 [GETMEM.INC # 2015]
01 0d98f978 004b443f 0d98f988 004890b8 108d5b20 MMIServer!SysReallocMem+0x2dc [GETMEM.INC # 3404]
02 0d98f998 0048910c 0d98f9f4 108c6af0 00482730 MMIServer!ReallocMem+0x13 [System.pas # 3521]
03 0d98f9ac 00488a40 09b60b58 108c6af0 0000f000 MMIServer!TMemoryStreamWrite+0x30 [Classes.pas # 6181]
04 0d98f9bc 00488b0e 0d98fa04 00488b3c 0d98f9f4 MMIServer!ClassesTStreamWriteBuffer+0x18 [Classes.pas # 5789]
05 0d98f9f4 0046d910 0000fc40 00000000 0d98fa10 MMIServer!ClassesTStreamCopyFrom+0xae [Classes.pas # 5814]
06 0d98fa38 0046dc85 0d98faec 0046dcec 0d98fad8 MMIServer!TOPToSoapDomConvertDOMToStream+0x80 [..\..\Patches\BDS2009\TByteDynArrayThroughSOAP\OPToSOAPDomConv.pas # 895]
07 0d98fad8 0052c272 01ca3930 10680b90 10d4daa8 MMIServer!TOPToSoapDomConvertMakeResponse+0x31d [..\..\Patches\BDS2009\TByteDynArrayThroughSOAP\OPToSOAPDomConv.pas # 987]
08 0d98fb94 0052eff9 0d98fcfb 10680b90 10680870 MMIServer!TSoapPascalInvokerInvoke+0x34e [SOAPPasInv.pas # 230]
09 0d98fc24 00526edb 0d98fcfb 10680b90 10680870 MMIServer!THTTPSoapPascalInvokerDispatchSOAP+0x20d [soaphttppasinv.pas # 82]
0a 0d98fd2c 00566d5b 10d1fee0 0d98fd6c 00566d83 MMIServer!THTTPSoapDispatcherDispatchRequest+0x28b [WebBrokerSOAP.pas # 223]
0b 0d98fd5c 00566e88 00000000 10d1fee0 0d98fda4 MMIServer!DispatchHandler+0x8b [HTTPApp.pas # 1511]
0c 0d98fd98 00567063 0046b308 0d98fdb0 0046b321 MMIServer!TCustomWebDispatcherDispatchAction+0xf0 [HTTPApp.pas # 1546]
0d 0d98fe10 0046b205 08dae450 02e3f360 09b21b70 MMIServer!TCustomWebDispatcherHandleRequest+0xb [HTTPApp.pas # 1594]
0e 0d98fe28 005b6e1f 08dae450 0d98fe40 005b6e43 MMIServer!TIdHTTPWebBrokerBridgeDoCommandGet+0x2d [..\..\Patches\Indy10\IdHTTPWebBrokerBridge.pas # 964]
0f 0d98fefc 005d86be 01c23370 005c7939 005c7783 MMIServer!IdcustomhttpserverTIdCustomHTTPServerDoExecute$qqrp20IdcontextTIdContext+0x683
10 0d98ff70 0048da71 0d98ff84 0048da7b 0d98ffa0 MMIServer!IdcontextTIdContextRun$qqrv+0x12
11 0d98ffa0 004b63f2 0d98ffdc 004b5e74 0d98ffb4 MMIServer!ThreadProc+0x45 [Classes.pas # 10892]
12 0d98ffb4 7c80b729 08b3e090 030afabc 00000000 MMIServer!ThreadWrapper+0x2a [System.pas # 13819]
CodeGear\RAD Studio\6.0\source\Win32\rtl\sys\getmem.inc:
2004 #GotBinAndGroup:
2005 {ebx = block size, ecx = bin number, edx = group number}
2006 push esi
2007 push edi
2008 {Get a pointer to the bin in edi}
2009 lea edi, [MediumBlockBins + ecx * 8]
2010 {Get the free block in esi}
2011 mov esi, TMediumFreeBlock[edi].NextFreeBlock
2012 {Remove the first block from the linked list (LIFO)}
2013 mov eax, TMediumFreeBlock[esi].NextFreeBlock
2014 mov TMediumFreeBlock[edi].NextFreeBlock, eax
>2015 mov TMediumFreeBlock[eax].PreviousFreeBlock, edi
2016 {Is this bin now empty?}
2017 cmp edi, eax
2018 jne #MediumBinNotEmptyForMedium
2019 {eax = bin group number, ecx = bin number, edi = #bin, esi = free block, ebx = block size}
2020 {Flag this bin as empty}
2021 mov eax, -2
2022 rol eax, cl
2023 and dword ptr [MediumBlockBinBitmaps + edx * 4], eax
2024 jnz #MediumBinNotEmptyForMedium
2025 {Flag the group as empty}
2026 btr MediumBlockBinGroupBitmap, edx
2027 #MediumBinNotEmptyForMedium:
Disassembly:
004b31d4 56 push esi
004b31d5 57 push edi
004b31d6 8d3ccd00be3201 lea edi,MMIServer!NeverSleepOnMMThreadContention+0x1ef (0132be00)[ecx*8]
004b31dd 8b7704 mov esi,dword ptr [edi+4]
004b31e0 8b4604 mov eax,dword ptr [esi+4]
004b31e3 894704 mov dword ptr [edi+4],eax
>004b31e6 8938 mov dword ptr [eax],edi ds:0023:00000000=????????
004b31e8 39c7 cmp edi,eax
004b31ea 7517 jne MMIServer!SystemSysGetMem$qqri+0x333 (004b3203)
004b31ec b8feffffff mov eax,0FFFFFFFEh
004b31f1 d3c0 rol eax,cl
004b31f3 21049580bd3201 and dword ptr MMIServer!NeverSleepOnMMThreadContention+0x16f (0132bd80)[edx*4],eax
004b31fa 7507 jne MMIServer!SystemSysGetMem$qqri+0x333 (004b3203)
004b31fc 0fb3157cbd3201 btr dword ptr [MMIServer!NeverSleepOnMMThreadContention+0x16b (0132bd7c)],edx
My understanding of this piece of code of getmem.inc is:
There is a double-linked list of free memory blocks.
One block is taken from this list.
The Double Linked List is reconnected.
In drawing:
|----------|--------------------->|----------|--------------------->|----------|
| | NextFreeBlock | | NextFreeBlock | |
| 132d408 | | 11290132 | | 00000000 |
| |<---------------------| |<---------------------| |
|----------| PreviousFreeBlock |----------| PreviousFreeBlock |----------|
^ ^ ^
| | |
edi esi eax
|----------|--------------------->|----------| |----------|
| | NextFreeBlock | | | |
| 132d408 | | 00000000 | | 11290132 |
| |<---------------------| | | |
|----------| PreviousFreeBlock |----------| |----------|
^ ^ ^
| | |
edi eax esi
Some registers:
eax 0
ebx 1e030
ecx 2c1
edx 16
edi 132d408
esi 11290132
ebp 1e000
eip 4b31e6
esp d98f958
There is a NULL pointer in the Double Linked Lists of the free memory blocks.
When writing the PreviousFreeBlock to this address the access violation occurred.
How can there be a NULL pointer in the Double Linked Lists of the free memory blocks?
Was the memory already corrupted?
Have anyone experienced the same problem in getmem.inc?
What can i do to investigate this crash further?

GDB is off by a line when debugging a nasm application

I just encountered a weird issue with gdb, though I'm not sure, if I'm missing something.
Let's suppose I have these two files:
somefile.asm:
01 section .text
02
03 funca:
04 mov eax, 5
05 mov ebx, 5
06 cmp eax, ebx
07 je aisequal
08 mov ecx, 13
09 mov edx, 19
10 ret
11
12 aisequal:
13 mov ecx, 17
14 mov edx, 21
15 ret
and
somefile_test.asm:
01 %include "somefile.asm"
02
03 section .text
04 global _start
05
06 _start:
07 xor eax, eax
08 xor ebx, ebx
09 xor ecx, ecx
10 xor edx, edx
11 call funca
12
13 mov eax, 1
14 mov ebx, 0
15 int 0x80
I compile and link it using
nasm -f elf -g -F dwarf somefile_test.asm
ld -m elf_i386 -o somefile_test.out somefile_test.o
And then debug my application using gdb:
gdb somefile_test.out
I now set a breakpoint in the imported file:
GNU gdb (GDB) 10.1
(gdb) b somefile.asm:5
Breakpoint 1 at 0x8049000: file somefile.asm, line 5.
(gdb) r
Starting program: /<bla>/somefile_test.out
Breakpoint , funca () at somefile.asm:5
5 mov ebx, 5
Now appearantly, the execution stopped at the correct position. The next line to be executed would be 5, which is mov ebx, 5.
However, the last line should've been mov eax, 5 which should have already been executed. It was not:
(gdb) i r eax
eax 0x0 0
It gets even weirder:
(gdb) si
6 cmp eax, ebx
(gdb) i r eax ebx
eax 0x5 5
ebx 0x0 0
Now, eax is set, but ebx is not (yet).
If I execute the next line, it is set:
(gdb) si
7 je aisequal
(gdb) i r eax ebx
eax 0x5 5
ebx 0x5 5
However, I'd expect the program to jump to line 12 (aisequal) now, but it doesn't:
(gdb) si
8 mov ecx, 13
On the next instruction, it suddenly goes to the right line:
(gdb) si
14 mov edx, 21
(gdb) i r eax ebx edx
eax 0x5 5
ebx 0x5 5
edx 0x0 0
And so on:
(gdb) si
15 ret
(gdb) i r eax ebx ecx edx
eax 0x5 5
ebx 0x5 5
ecx 0x11 17
edx 0x0 0
If I put all my code in a single file, everything works as expected:
01 section .text
02 global _start
03
04 _start:
05 xor eax, eax
06 xor ebx, ebx
07 xor ecx, ecx
08 xor edx, edx
09 call funca
10
11 mov eax, 1
12 mov ebx, 0
13 int 0x80
14
15 funca:
16 mov eax, 5
17 mov ebx, 5
18 cmp eax, ebx
19 je aisequal
20 mov ecx, 13
21 mov edx, 19
22 ret
23
24 aisequal:
25 mov ecx, 17
26 mov edx, 21
27 ret
GBU gdb (GDB) 10.1
(gdb) b 16
Breakpoint 1 at 0x8049019: file singlefile.asm, line 16.
(gdb) r
Starting program: /<bla>/singlefile.out
Breakpoint 1, funca () at singlefile.asm:16
16 mov eax, 5
(gdb) i r eax ebx ecx edx
eax 0x0 0
ebx 0x0 0
ecx 0x0 0
edx 0x0 0
(gdb) si
17 mov ebx, 5
(gdb) i r eax ebx ecx edx
eax 0x5 5
ebx 0x0 0
ecx 0x0 0
edx 0x0 0
(gdb) si
18 cmp eax, ebx
(gdb) si
19 je aisequal
(gdb) si
25 mov ecx, 17
(gdb) si
26 mov edx, 21
(gdb) i r eax ebx ecx edx
eax 0x5 5
ebx 0x5 5
ecx 0x11 17
edx 0x0 0
(gdb) si
aisequal () at singlefile.asm:27
27 ret
(gdb) i r eax ebx ecx edx
eax 0x5 5
ebx 0x5 5
ecx 0x11 17
edx 0x15 21
(gdb) si
_start () at singlefile.asm:11
11 mov eax, 1
Now I've only picked up gdb two days ago, so I'm not that familiar with it.
Can someone explain to me what's happening?
Is this a bug or am I missing something?
I am using
nasm 2.15.05-1
binutils 2.35.1-1
gdb 10.1-4
gcc 10.2.0-4
on Linux 5.9.14-arch1-1 #1 SMP PREEMPT Sat, 12 Dec 2020 14:37:12 +0000 x86_64 GNU/Linux
This looks like a bug in nasm. It didn't reproduce for me using nasm-2.14.
GDB will only display source info that the compiler/assembler tells it. If the assembler puts out incorrect info, then GDB will display that incorrect info and can't do anything about it.
To verify that the problem is in nasm, run objdump -dS somefile_test.o and compare the assembly and source listing. If they are also off by one, it's a bug in nasm.
Here is what I see:
somefile_test.o: file format elf32-i386
Disassembly of section .text:
00000000 <funca>:
section .text
funca:
mov eax, 5
0: b8 05 00 00 00 mov $0x5,%eax
mov ebx, 5
5: bb 05 00 00 00 mov $0x5,%ebx
cmp eax, ebx
a: 39 d8 cmp %ebx,%eax
je aisequal
c: 74 0b je 19 <aisequal>
Note how instructions and source perfectly line up.
Apparently, this is a regression in nasm.
Reported it to them.

Getting return value of syscall in assembly

I'm writing a simple assembly program on Darwin x86_64 (MacOS 10.14.6) that creates a file (test.txt) and writes "E" to it. However, for some reason, the "E" is not written to the file. What am I doing wrong?
Here's my program:
global start
section .text
start:
;Create the file
mov rax, 0x2000005
mov rdi, fname
mov rsi, 0x200
mov rdx, 0o644
syscall
;Write to file
mov rdi, rax ;As far as I know, this uses the fd returned by creating a file (previous syscall)
mov rsi, msg
mov rdx, 1
mov rax, 0x2000004
syscall
;Exit
mov rax, 0x2000001
mov rdi, 0
syscall
section .data
msg: db "E" ;Message
fname: db "test.txt" ;File name
I have also tried this:
global start
section .text
start:
mov rax, 0x2000005
mov rdi, fname
mov rsi, 0x200
mov rdx, 0o644
syscall
mov rdi, rax
mov rsi, msg
mov rdx, 2
mov rax, 0x2000004
syscall
mov rax, 0x2000001
mov rdi, 0
syscall
section .data
msg: db "E", -1
fname: db "test.txt", 0
Yet neither work.
I found the answer:
I found that opening the file with create mode and write mode works.
global start
section .text
start:
;Open file with create mode and write mode
mov rax, 0x2000005
mov rdi, fname
mov rsi, 0x201
mov rdx, 0o644
syscall
;Now write
mov rdi, rax
mov rsi, msg
mov rdx, 1
mov rax, 0x2000004
syscall
;Exit
mov rax, 0x2000001
mov rdi, 0
syscall
section .data
msg: db "E"
fname: db "test.txt"
Also, here is an array of flags for opening files:
O_ACCMODE: 0x3
O_APPEND: 0x8
O_ASYNC: 0x40
O_CLOEXEC: 0x1000000
O_CREAT: 0x200
O_DIRECTORY: 0x100000
O_DSYNC: 0x400000
O_EXCL: 0x800
O_EXLOCK: 0x20
O_NDELAY: 0x4
O_NOCTTY: 0x20000
O_NOFOLLOW: 0x100
O_NONBLOCK: 0x4
O_RDONLY: 0x0
O_RDWR: 0x2
O_SHLOCK: 0x10
O_SYNC: 0x80
O_TRUNC: 0x400
O_WRONLY: 0x1
To combine, use the | operator (in C) or or (in assembly).

What's wrong with my NASM program?

I recently started programming in assembly language and could get something wrong. This code is supposed to write out "21947392":
section .data
nl db 10
section .bss
number resb 19
.end resb 1
section .text
GLOBAL start
start:
mov rdi, 21947392
call _printNumber
mov rax, 0x2000001
xor rdi, rdi
syscall
_printNumber:
mov rcx, 10
mov rsi, number.end
mov rax, rdi
_loop:
xor rdx, rdx
div rcx
add rdx, 48
mov [rsi], rdx
dec rsi
cmp rax, 0
jne _loop
mov rdi, rsi
inc rdi
mov rsi, number.end
sub rsi, rdi
call _print
mov rdi, nl
mov rsi, 1
call _print
ret
_print:
mov rax, 0x2000004
mov rdx, rsi
mov rsi, rdi
mov rdi, 1
syscall
ret
It is written for macOS x64 on NASM and it only prints "2" (and seems to even differ from one assembly to another)...
Here are the commands I use in terminal:
nasm -f macho64 -o printNumber.o printNumber.asm
ld printNumber.o -o printNumber
./printNumber
Please, help find what's wrong.

Resources